題解 P3855 【[TJOI2008]Binary Land】
阿新 • • 發佈:2021-06-23
演算法分析:BFS
顯然是爆搜題(雖然不知道為什麼有 dp 標籤)(霧)。
首先是狀態,我們應該記錄兩隻企鵝的位置和走到當前狀態所需的步數,如果走過這個狀態,那麼不再重複走。
struct P {
int x,y,a,b,step;//位置,步數
}g,m;
其次是對狀態的可行性檢查。我在檢查狀態完畢後直接對狀態進行了修改,這樣可以使 BFS 主體簡短一點。
inline bool check(int &x,int &y,int &a,int &b,P t) { //t 是沒移動之前的狀態 if(pc[x][y]=='X'||pc[a][b]=='X'){//蜘蛛網,失敗 vis[x][y][a][b]=1; return false; } if(pc[x][y]=='#')vis[x][y][a][b]=1,x=t.x,y=t.y;//其中一隻撞到了,就往回退 if(pc[a][b]=='#')vis[x][y][a][b]=1,a=t.a,b=t.b;//另一隻... if(vis[x][y][a][b])return false;//如果兩隻都撞到了,那麼vis一定被標記過,退出 vis[x][y][a][b]=1;//沒走過的狀態,標記一下 return true; }
最後是一些小技巧。比如說,預處理兩隻企鵝的移動,記錄在陣列 \(g_1\) 和 \(g_2\) 裡。在預處理時,直接將兩隻企鵝的移動方式對應起來,這樣在移動時比較方便(詳見程式碼)。
下面是喜聞樂見的程式碼:
#include<bits/stdc++.h> #define reg register using namespace std; const int N=50; bool vis[N][N][N][N]; char pc[N][N]; int g1[10][2] {1,0,0,-1,0,1,-1,0}; int g2[10][2] {1,0,0,1,0,-1,-1,0}; //g1 和 g2 在儲存時直接對應起來 struct P { int x,y,a,b,step;//位置,步數 }g,m; inline bool check(int &x,int &y,int &a,int &b,P t) { //t 是沒移動之前的狀態 if(pc[x][y]=='X'||pc[a][b]=='X'){//蜘蛛網,失敗 vis[x][y][a][b]=1; return false; } if(pc[x][y]=='#')vis[x][y][a][b]=1,x=t.x,y=t.y;//其中一隻撞到了,就往回退 if(pc[a][b]=='#')vis[x][y][a][b]=1,a=t.a,b=t.b;//另一隻... if(vis[x][y][a][b])return false;//如果兩隻都撞到了,那麼vis一定被標記過,退出 vis[x][y][a][b]=1;//沒走過的狀態,標記一下 return true; } inline void bfs(int xx,int yy,int aa,int bb) { queue<P> q; q.push({xx,yy,aa,bb,0}); vis[xx][yy][aa][bb]=1; while(!q.empty()) { reg P t=q.front(); q.pop(); for(reg int i=0; i<4; i++) { reg int x=t.x+g1[i][0],y=t.y+g1[i][1];//移動 reg int a=t.a+g2[i][0],b=t.b+g2[i][1]; if(check(x,y,a,b,t)) { if(pc[x][y]=='T'&&pc[a][b]=='T') {//走到終點了 printf("%d",t.step+1); exit(0); } q.push({x,y,a,b,t.step+1}); } } } } int main() { cin.tie(0); reg int r,c; cin>>r>>c; for(reg int i=1;i<=r;i++){ for(reg int j=1;j<=c;j++){ cin>>pc[i][j]; if(pc[i][j]=='G')g={i,j};//Gurin位置 if(pc[i][j]=='M')m={i,j};//Malon位置 } } bfs(g.x,g.y,m.x,m.y); cout<<"no"; return 0; }
(目前最優解)
歡迎交流討論,請點個贊哦~