HDU3085-nightmare2(雙向BFS)
阿新 • • 發佈:2018-11-10
這道題給人的第一感覺就是非常繁瑣,因為要考慮兩個人狀態以外還要考慮鬼對人的影響,一開始是想讓鬼也寬搜,然後每次都去考慮這個地方的位置是否已經被鬼覆蓋過。
但是我們如果注意到鬼是可以穿過牆的,也就是說我們通過曼哈頓距離就可以判斷出鬼能覆蓋的位置,這樣我們只需要通過一個簡單的計算來判定是否這個地方可以走就可以了。
那麼我們要考慮就是一個普通的雙向BFS,我們分別記錄下這兩人的初始位置,然後我們這裡還要學習到一個小的技巧,那就是對於BFS的佇列,我們其實是可以控制每一次出隊的結點的深度,我們只要儲存下現有佇列的元素個數,然後讓這些點出隊,就可以實現這個功能,然後我麼每次走到一個新的點都去判斷一下這個點是不是已經被對方打上了標記,如果有,那就說明這兩個人最終是相遇的。
這道BFS說難也並沒有特別難,最關鍵的還是要多積累,把題目的思路給理順,同諸位共勉。
#include<bits/stdc++.h> using namespace std; const int maxn=8e2+50; char mp[maxn][maxn]; int n,m,gx[2],gy[2],stx,sty,edx,edy,vis[2][maxn][maxn],step=0,cnt=0; int dx[4]={0,0,1,-1}; int dy[4]={-1,1,0,0}; struct node{ int x,y; node(){} node(int xx,int yy):x(xx),y(yy){} }; queue<node> q[2]; bool check(node u) { int x=u.x,y=u.y; if(x<1||x>n||y<1||y>m||mp[x][y]=='X') return 0; if(( abs(x-gx[0])+abs(y-gy[0])<=2*step )||( abs(x-gx[1])+abs(y-gy[1])<=2*step) ) return 0; return 1; } int bfs(int w) { int V=q[w].size(); while(V--) { node u=q[w].front();q[w].pop(); if(!check(u)) continue; for(int i=0;i<4;i++){ int nx=u.x+dx[i]; int ny=u.y+dy[i]; if(!check(node(nx,ny))) continue; if(!vis[w][nx][ny]){ if(vis[w^1][nx][ny]) return 1; vis[w][nx][ny]=1; q[w].push(node(nx,ny)); } } } return 0; } int solve() { vis[0][stx][sty]=1,vis[1][edx][edy]=1; q[0].push(node(stx,sty));q[1].push(node(edx,edy)); while(!q[0].empty()||!q[1].empty()) { ++step; if(bfs(0)) return step; if(bfs(0)) return step; if(bfs(0)) return step; if(bfs(1)) return step; } return -1; } void clear(){ cnt=0,step=0; memset(vis,0,sizeof(vis)); while(!q[0].empty()) q[0].pop(); while(!q[1].empty()) q[1].pop(); } int main(){ ios::sync_with_stdio(false); cin.tie(0); int line; cin>>line; while(line--) { clear(); cin>>n>>m; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { cin>>mp[i][j]; if(mp[i][j]=='Z') gx[cnt]=i,gy[cnt]=j,++cnt; if(mp[i][j]=='M') stx=i,sty=j; if(mp[i][j]=='G') edx=i,edy=j; } cout<<solve()<<endl; } return 0; }