N∗M N*M的棋盘上有一个受伤的国王与一个要去救援国王的骑士,他们每个单位时间必须同时移动一次寻找对方。如下图所示,黑色的图例表示国王(右)或骑士(左)当前所在的位置,那么灰色的位置表示在一次移动中他们可能到达的位置。国王伤势严重,因此他必须在K个单位时间内得到骑士的救援,否则会挂掉。问国王是否可以在K个单位时间内获得救援,如果可以,最短需要花多少个单位时间。
//双向BFS广搜
#include <queue> #include <cstdio> #include <string> #include <cstring> #include <iostream> #define clr(a,val) memset(a,val,sizeof(a)) using namespace std; const int maxn = 1005; const int INF = 0x3f3f3f3f; struct SPoint { int x,y,step; }; int N,M,K; SPoint Knight,King,Now,Next; queue<SPoint>Que; int Map_Knight[maxn][maxn],Map_King[maxn][maxn]; bool vis[maxn][maxn]; const int dirX_Knight[8] = {-1,-2,-2,-1,1,2,2,1}; const int dirY_Knight[8] = {-2,-1,1,2,-2,-1,1,2}; const int dirX_King [8] = {-1,0,-1,1,-1,1,0,1 }; const int dirY_King [8] = {-1,-1,0,1,1,-1,1,0 }; bool Over_Bound(const SPoint &p) { return p.x <= 0 || p.y <= 0 || p.x > N || p.y > M; } void BFS_Knight() { clr(vis,false); clr(Map_Knight,-1); while(!Que.empty()) Que.pop(); Que.push(Knight); vis[Knight.x][Knight.y] = true; while(!Que.empty()) { Now = Que.front(); Map_Knight[Now.x][Now.y] = Now.step; for(int i = 0; i < 8; i++) { Next.x = Now.x + dirX_Knight[i]; Next.y = Now.y + dirY_Knight[i]; Next.step = Now.step + 1; //Next.step > K 剪枝处理 if(Over_Bound(Next) || vis[Next.x][Next.y] || Next.step > K) continue; vis[Next.x][Next.y] = true; Que.push(Next); } Que.pop(); } } void BFS_King() { clr(vis,false); clr(Map_King,-1); while(!Que.empty()) Que.pop(); Que.push(King); vis[King.x][King.y] = true; while(!Que.empty()) { Now = Que.front(); Map_King[Now.x][Now.y] = Now.step; for(int i = 0; i < 8; i++) { Next.x = Now.x + dirX_King[i]; Next.y = Now.y + dirY_King[i]; Next.step = Now.step + 1; //Next.step > K 剪枝处理 if(Over_Bound(Next) || vis[Next.x][Next.y] || Next.step > K) continue; vis[Next.x][Next.y] = true; Que.push(Next); } Que.pop(); } } int main() { freopen("F:\\in.dat","r",stdin); int t,cas = 0,ans; cin>>t; while(t--) { cin>>N>>M>>K; cin>>King.x>>King.y; cin>>Knight.x>>Knight.y; King.step = Knight.step = 0; BFS_Knight(); BFS_King(); ans = INF; //初始化为无穷大 //关键得好好理解下面的代码~ for(int i = 1; i <= N; i++) { for(int j = 1; j <= M; j++) { int& Step_King = Map_King[i][j], &Step_Knight = Map_Knight[i][j]; if(Step_King == -1 || Step_Knight == -1) continue; //分类的主要依据就是国王的走法和骑士不同 //如果国王比骑士先到该点,国王可以现在该点附近转一下,并不影响骑士到达该点的步数~ if(Step_Knight > Step_King) { ans = min(ans, Step_Knight); continue; } //如果国王比骑士到达该点要多走的步数为奇数 if((Step_King - Step_Knight) & 1) { ans = min(ans,Step_King + 1); continue; } //如果国王比骑士到达该点要多走的步数为偶数 ans = min(ans,Step_King); continue; } } printf("Case #%d:\n",++cas); if(ans > K) printf("OH,NO!\n"); else printf("%d\n",ans); } return 0; }