把国王和骑士的位置都转换成相对位置。国王必须在骑士的右下方(计算方便)
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; }