下棋
N∗M
的棋盘上有一个受伤的国王与一个要去救援国王的骑士,他们每个单位时间必须同时移动一次寻找对方。如下图所示,黑色的图例表示国王(右)或骑士(左)当前所在的位置,那么灰色的位置表示在一次移动中他们可能到达的位置。国王伤势严重,因此他必须在K个单位时间内得到骑士的救援,否则会挂掉。问国王是否可以在K个单位时间内获得救援,如果可以,最短需要花多少个单位时间。
第一行包含一个整数 T,(1≤T≤50) 代表测试数据的组数,接下来 T 组测试数据。 每组测试数据第一行包含三个整数 N,M,K , 且 2≤N,M≤1000 , 1≤K≤200 。第二行两个整数 X king ,Y king ,对应国王所在方格的坐标。第三行两个整数 X knight ,Y knight ,对应骑士所在方格的坐标。其中 1≤X king ,X knight ≤N,1≤Y king ,Y knight ≤M ,保证骑士与国王一开始不在同一个方格内且他们都可以移动。:
对于每组测试数据,输出两行: 第一行输出:"Case #i:"。 i 代表第 i 组测试数据。 第二行输出测试数据的结果,如果国王可以得到救援,则输出最快需要花多少个单位时间。否则,输出“OH,NO!”。
2 3 2 1 1 1 3 1 3 3 1 1 1 1 2
Case #1: 1 Case #2: OH,NO!
//方法是双向BFS加特殊判断
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <cmath>
using namespace std;
const int maxn=1000+5;
/*这是位置数组*/
int xk[8]= {-1,0,-1,1,-1,1,0,1};
int yk[8]= {-1,-1,0,1,1,-1,1,0};
int xnk[8]= {-1,-2,-2,-1,1,2,2,1};
int ynk[8]= {-2,-1,1,2,-2,-1,1,2};
int T,N,M,K,kingx,kingy,kningx,kningy;
int kingstep[maxn][maxn];//国王的最少步的记录
int kningstep[maxn][maxn];//骑士最少步的记录(可以不设,直接在BFS中进行判断)
bool vis[maxn][maxn];//是否访问过
//结构体,y代表着纵坐标,x代表着横坐标
struct POS {
int x,y,step;
POS(int x,int y,int step) {
this->x=x;
this->y=y;
this->step=step;
}
};
//求国王的最少步
void BFS1() {
queue<POS>G;
memset(vis,false,sizeof(vis));
memset(kingstep,-1,sizeof(kingstep));//代表现在都不能到达
G.push(POS(kingx,kingy,0));
vis[kingy][kingx]=true;
while(!G.empty()) {
POS CUR=G.front();
G.pop();
kingstep[CUR.y][CUR.x]=CUR.step;
for(int i=0; i<8; i++) {
int nx=CUR.x+xk[i];
int ny=CUR.y+yk[i];
if(nx>N||nx<1||ny>M||ny<1||vis[ny][nx])continue;
vis[ny][nx]=true;
G.push(POS(nx,ny,CUR.step+1));
}
}
}
//求骑士的最少步(可以去掉这一部分代码,将这部分代码简写在第一个BFS中,只要加个判断,大家可以试试)
void BFS2() {
int cnt=0;
queue<POS>G;
memset(vis,false,sizeof(vis));
memset(kningstep,-1,sizeof(kningstep));//代表现在都不能到达
G.push(POS(kningx,kningy,0));
vis[kningy][kningx]=true;
while(!G.empty()) {
POS CUR=G.front();
G.pop();
kningstep[CUR.y][CUR.x]=CUR.step;
for(int i=0; i<8; i++) {
int nx=CUR.x+xnk[i];
int ny=CUR.y+ynk[i];
if(nx>N||nx<1||ny>M||ny<1||vis[ny][nx])continue;
vis[ny][nx]=true;
G.push(POS(nx,ny,CUR.step+1));
}
}
}
int main() {
freopen("D://imput.txt","r",stdin);
scanf("%d",&T);
for(int i=1; i<=T; i++) {
scanf("%d%d%d",&N,&M,&K);
scanf("%d%d",&kingx,&kingy);
scanf("%d%d",&kningx,&kningy);
BFS1();
BFS2();
int maxs=1100000;
//目的是得到最少步
for(int k=1; k<=M; k++) {
for(int j=1; j<=N; j++) {
if(kingstep[k][j]!=-1&&kningstep[k][j]!=-1) {//首先必须可以到达
int temp;
if(kningstep[k][j]>kingstep[k][j]) {//当骑士的步数打与国王时,只需要记录骑士的步数
temp=kningstep[k][j]; //原因是因为,国王的移动方向是相邻的八个位置,当骑士的步数大于国王时,不管
} else { //不管这之间差多少,不管是奇数还是偶数,国王都能在这相差多少的范围内到达指定的位置)
//就是骑士所在的位置。
if((kingstep[k][j]-kningstep[k][j])%2==0) {//由于骑士的走法特殊,所以当他的步数少了的时候,那么就得在原地来回走偶数步,
//回到回来的位置与国王相遇
temp=kingstep[k][j];//国王的步数大。记录国王的步数
} else {
temp=kingstep[k][j]+1;//跟骑士的步数大于国王有点类似,当相差奇数的时候,国王不许要多花一步才能与骑士相遇。
}
}
maxs=min(maxs,temp);//得到所有步数中最少的
}
}
}
printf("Case #%d:\n",i);
if(K>=maxs) {//在规定的时间内找到的话输出答案。
printf("%d\n",maxs);
} else {
printf("OH,NO!\n");
}
}
return 0;
}
题解二:找规律
//此方法就是找规律找取边以及国王骑士移动的规律
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
int n , m , k;
int main() {
int t , len , cas = 0 , i , j ;
char ch ;
scanf( "%d", &t );
while ( cas < t ) {
int x , y , xx, yy , ans , a , b ;
cas++;
printf( "Case #%d:\n", cas );
scanf( "%d%d%d", &n, &m, &k );
scanf( "%d%d", &x, &y );
scanf( "%d%d", &xx, &yy );
a = abs( x - xx ) ;
b = abs( y - yy ) ;
if ( ( a == 2 && b == 1 && ( y == 1 || y == m ) ) || ( a == 1 && b == 2 && ( x == 1 || x == n ) ) ) {
ans = 2;
} else if ( a == 1 && b == 1 && ( x == 1 || x == n ) && ( y == 1 || y == m ) ) {
ans = 2 ;
} else if ( ( a == 0 && b == 1 && ( y == 1 || y == m ) ) || ( a == 1 && b == 0 && ( x == 1 || x == n ) ) ) {
ans = 2 ;
} else {
if ( a < b ) {
int g = a ;
a = b ;
b = g ;
}
if ( a / 3 * 2 <= b ) {
ans = ( a + b ) / 5 ;
if ( ( a + b ) % 5 ) {
ans ++ ;
}
} else {
ans = a / 3 ;
if ( a % 3 ) {
ans ++ ;
}
}
}
if ( ans > k ) {
printf( "OH,NO!\n" );
} else {
printf( "%d\n", ans );
}
}
return 0 ;
}