1. 程式人生 > >洛谷 P3956 棋盤(BFS)

洛谷 P3956 棋盤(BFS)

傳送門:Problem P3956

https://www.cnblogs.com/violet-acmer/p/9827010.html

 

題解:

  BFS

  相關變數解釋:

    color[maxn][maxn];...................................color[ i ][ j ] : ( i , j )點的顏色,-1代表無色
    dp[maxn][maxn];.......................................dp[ i ][ j ] : 從( 1 , 1 )點到( i , j )點需要花費的最少金幣
    magic[maxn][maxn];..................................magic[ i ][ j ] : 判斷 ( i , j )點是否使用魔法
    in[maxn][maxn];.........................................in[ i ][ j ] : 判斷( i , j )點是否在佇列中

  具體步驟:

    初始,將(1,1)點加入佇列中;

    (1):儲存隊頭元素並彈出

    (2):每次,判斷當前點的上下左右點是否可以通過當前點使dp[ ][ ]變小,如果可以,更新dp[ ][ ],如果被更新的點不在佇列中,加入佇列

    (3):重複(2)過程,直到佇列為空

AC程式碼:

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<queue>
  4 #include<cstring>
  5 using namespace
std; 6 #define INF 0x3f3f3f3f 7 #define P pair<int ,int > 8 #define mem(a,b) memset(a,b,sizeof a) 9 const int maxn=100+50; 10 11 int m,n; 12 int color[maxn][maxn]; 13 int dp[maxn][maxn]; 14 bool marge[maxn][maxn]; 15 bool in[maxn][maxn]; 16 queue<P >myqueue; 17 int dx[4]={-1
,1,0,0}; 18 int dy[4]={0,0,-1,1}; 19 bool isSat(int val) 20 { 21 return val >= 1 &&val <= m; 22 } 23 void Solve() 24 { 25 dp[1][1]=0;//初始化dp[1][1],並將其加入到佇列中 26 myqueue.push(P(1,1)); 27 while(!myqueue.empty())//步驟(3) 28 { 29 P p=myqueue.front();//步驟(1) 30 myqueue.pop(); 31 in[p.first][p.second]=false; 32 for(int i=0;i < 4;++i)//步驟(2) 33 { 34 int x=p.first+dx[i]; 35 int y=p.second+dy[i]; 36 if(isSat(x) && isSat(y)) 37 { 38 if(!marge[p.first][p.second])//如果當前點的未使用過魔法的,也就意味這當前點的顏色是本身就有的 39 { 40 if(!marge[x][y])//如果與當前點相鄰的點(x,y)也為曾使用過魔法 41 { 42 if(color[x][y] != -1)//如果點(x,y)有色,但並不是因為魔法而產生的 43 { 44 //如果當前點可以放縮dp[x][y] 45 if(dp[x][y] > dp[p.first][p.second]+(color[x][y] != color[p.first][p.second])) 46 { 47 dp[x][y]=dp[p.first][p.second]+(color[x][y] != color[p.first][p.second]); 48 if(!in[x][y])//被放縮的點(x,y)如果不在佇列中,加入佇列 49 in[x][y]=true,myqueue.push(P(x,y)); 50 } 51 } 52 else//如果無色,通過使用魔法將其變為與當前點顏色相同的點,並被放縮了dp[][] 53 { 54 marge[x][y]=true; 55 color[x][y]=color[p.first][p.second]; 56 dp[x][y]=dp[p.first][p.second]+2; 57 if(!in[x][y]) 58 in[x][y]=true,myqueue.push(P(x,y)); 59 } 60 } 61 else if(dp[x][y] > dp[p.first][p.second]+2)//如果點(x,y)在之前使用過魔法,就需要判斷,當前為使用過魔法的點是否可以放縮dp[x][y] 62 { 63 dp[x][y]=dp[p.first][p.second]+2; 64 color[x][y]=color[p.first][p.second]; 65 if(!in[x][y]) 66 in[x][y]=true,myqueue.push(P(x,y)); 67 } 68 } 69 else if(!marge[x][y] && color[x][y] != -1)//如果當前點的使用過魔法的,也就意味這當前點的顏色是通過魔法變來的,那麼,只有當其臨近點(x,y)含有的顏色是其本身就有的才有資格判斷是否可以被放縮 70 { 71 if(dp[x][y] > dp[p.first][p.second]+(color[x][y] != color[p.first][p.second])) 72 { 73 dp[x][y]=dp[p.first][p.second]+(color[x][y] != color[p.first][p.second]); 74 if(!in[x][y]) 75 myqueue.push(P(x,y)),in[x][y]=true; 76 } 77 } 78 } 79 } 80 } 81 printf("%d\n",dp[m][m] == INF ? -1:dp[m][m]); 82 } 83 void Init() 84 { 85 mem(dp,INF); 86 mem(in,false); 87 mem(marge,false); 88 mem(color,-1); 89 } 90 int main() 91 { 92 scanf("%d%d",&m,&n); 93 Init(); 94 for(int i=1;i <= n;++i) 95 { 96 int x,y; 97 scanf("%d%d",&x,&y); 98 scanf("%d",&color[x][y]); 99 } 100 Solve(); 101 }
View Code