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;
}