把国王和骑士的位置都转换成相对位置。国王必须在骑士的右下方(计算方便)
10*10的表打出来是这样的(红色表示骑士位置,其他点的数字表示骑士走到这里需要花几步)
4 1 2 1 4 3 2 3 4 5
1 2 3 2 1 2 3 4 3 4
2 3 2 3 2 3 2 3 4 5
1 2 3 2 1 2 3 4 3 4
4 1 2 1 4 3 2 3 4 5
3 2 3 2 3 2 3 4 3 4
2 3 2 3 2 3 4 3 4 5
3 4 3 4 3 4 3 4 5 4
4 3 4 3 4 3 4 5 4 5
5 4 5 4 5 4 5 4 5 6
遍历一个范围(怎么找下面会说)内的所有点,如果国王到这个点的最少步数等于这个点上的值,那么它就是我们要找的答案之一了。我们要找答案里面的最小值。
那么怎么找这个范围?这里思考麻烦了点。首先计算出它们的相对距离dx,dy。但是题目不是还给了一个原本格子的范围n和m吗,这个范围是有用的。如果国王在骑士的右边,就取骑士右边的范围。反过来一样考虑。
这题还有个陷阱:不要把骑士和国王的走法弄反了。
#include<iostream>
#include<algorithm>
#include<string>
#include<map>
#include<vector>
#include<cmath>
#include<queue>
#include<string.h>
#include<stdlib.h>
#include<stdio.h>
#define ll long long
using namespace std;
ll v[1010][1010];
struct node{
int a,b;
ll c;
};
int x,y;
void bfs(){
node p;
p.a=2;
p.b=2;
p.c=0;
queue<node> q;
q.push(p);
while(!q.empty()){
node fr=q.front();
node w;
q.pop();
if(fr.a-1>=0&&fr.b-2>=0&&v[fr.a-1][fr.b-2]==-1){
v[fr.a-1][fr.b-2]=fr.c+1;
w.a=fr.a-1;w.b=fr.b-2;w.c=fr.c+1;
q.push(w);
}
if(fr.a-2>=0&&fr.b-1>=0&&v[fr.a-2][fr.b-1]==-1){
v[fr.a-2][fr.b-1]=fr.c+1;
w.a=fr.a-2;w.b=fr.b-1;w.c=fr.c+1;
q.push(w);
}
if(fr.a+1<=1005&&fr.b+2<=1005&&v[fr.a+1][fr.b+2]==-1){
v[fr.a+1][fr.b+2]=fr.c+1;
w.a=fr.a+1;w.b=fr.b+2;w.c=fr.c+1;
q.push(w);
}
if(fr.a+2<=1005&&fr.b+1<=1005&&v[fr.a+2][fr.b+1]==-1){
v[fr.a+2][fr.b+1]=fr.c+1;
w.a=fr.a+2;w.b=fr.b+1;w.c=fr.c+1;
q.push(w);
}
if(fr.a-1>=0&&fr.b+2<=1005&&v[fr.a-1][fr.b+2]==-1){
v[fr.a-1][fr.b+2]=fr.c+1;
w.a=fr.a-1;w.b=fr.b+2;w.c=fr.c+1;
q.push(w);
}
if(fr.a-2>=0&&fr.b+1<=1005&&v[fr.a-2][fr.b+1]==-1){
v[fr.a-2][fr.b+1]=fr.c+1;
w.a=fr.a-2;w.b=fr.b+1;w.c=fr.c+1;
q.push(w);
}
if(fr.a+1<=1005&&fr.b-2>=0&&v[fr.a+1][fr.b-2]==-1){
v[fr.a+1][fr.b-2]=fr.c+1;
w.a=fr.a+1;w.b=fr.b-2;w.c=fr.c+1;
q.push(w);
}
if(fr.a+2<=1005&&fr.b-1>=0&&v[fr.a+2][fr.b-1]==-1){
v[fr.a+2][fr.b-1]=fr.c+1;
w.a=fr.a+2;w.b=fr.b-1;w.c=fr.c+1;
q.push(w);
}
}
}
int main(){
memset(v,-1,sizeof(v));
v[2][2]=2;
bfs();
int t;
cin>>t;
int cnt=0;
int n,m,k;
while(t--){
printf("Case #%d:\n",++cnt);
cin>>n>>m>>k;
int x1,y1,x2,y2,row,col;
cin>>x1>>y1>>x2>>y2;
x=abs(x1-x2)+2;y=abs(y1-y2)+2;
if(x1>=x2)
row=n-x2+2;
else
row=x2-1+2;
if(y1>=y2)
col=m-y2+2;
else
col=y2-1+2;
ll s=100000000010;
for(int i=2;i<=min(1004,min(x+2,row));++i){
for(int j=2;j<=min(1004,min(y+2,col));++j){
if(v[i][j]==max(abs(x-i),abs(y-j)))
s=min(s,v[i][j]);
}
}
if(s<=k)
cout<<s<<endl;
else
cout<<"OH,NO!"<<endl;
}
return 0;
}
直接分析的方法(bfs最短路):
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <iostream>
#include <algorithm>
#include <vector>
#include <map>
#include <set>
#include <queue>
#include <assert.h>
#define clr(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long LL;
int T;
int n, m, k;
int g[1010][1010];
int dx[8] = {-1,-2,-2,-1,1,2,2,1};
int dy[8] = {-2,-1,1,2,-2,-1,1,2};
int x,y,xx,yy;
queue<pair<int,int> > q;
int main()
{
scanf("%d",&T);
int cas = 1;
while(T--)
{
scanf("%d%d%d",&n,&m,&k);
scanf("%d%d",&x,&y);
scanf("%d%d",&xx,&yy);
int ans = max(abs(x-xx), abs(y-yy) );
if(ans % 2 == 1) ans++;
printf("Case #%d:\n", cas++);
clr(g, -1);
while(!q.empty()) q.pop();
g[xx][yy] = 0;
q.push(make_pair(xx, yy));
while(!q.empty())
{
pair<int,int> h = q.front();
q.pop();
int curx = h.first;
int cury = h.second;
if(g[curx][cury] > k)
continue;
for(int i=0; i<8; i++)
{
int nx = curx + dx[i];
int ny = cury + dy[i];
if(nx < 1 || nx > n || ny < 1 || ny > m || g[nx][ny] != -1)
continue;
g[nx][ny] = g[curx][cury] + 1;
q.push(make_pair(nx, ny));
int t1 = g[nx][ny];
int t2 = max(abs(nx - x), abs(ny - y));
int t;
if(t2 == 0) //这个点跟国王重合
{
if(t1 == 0) t = 2; //国王和骑士都走出一步再回到原点
else if(t1 == 1) t = 3; //国王走三步回到原点,骑士走出一步再回到原点再走出一步
else t = t1;
}
else if(t1 >= t2) t = t1; //骑士的步数比国王多
else
{
if( (t2 - t1) % 2 == 0 ) t = t2;
else t = t2 + 1; //最后国王的步数多余了一步
}
ans = min(ans, t);
}
}
if(ans > k)
puts("OH,NO!");
else
printf("%d\n", ans);
}
return 0;
}