题目
有一个n×m的棋盘,在某个点(x,y)上有一个马,要求你计算出马到达棋盘上任意一个点最少要走几步。
输入输出格式
输入格式
输入只有一行四个整数,分别为n,m,x,y。
输出格式
一个n×m的矩阵,代表马到达某个点最少要走几步(不能到达则输出−1)。
输入输出样例
输入样例
3 3 1 1
输出样例
0 3 2
3 -1 1
2 1 4
解析
这道题目使用的是广度优先搜索,会优先考虑每种状态和初始状态的距离,形象点说,与初始状态越接近的情况就会越先考虑。再具体一点:每个时刻(阶段)要做的事情就是从上个时刻(阶段)每个状态扩展出新的状态。
广度优先搜索使用队列实现:先将初始状态加入到空的队列中,然后每次去除队首,找出队首所能转移到的状态,再将其压入队列;如此反复,直到对列为空。这样就能保证一个状态在被访问的时候一定是采用的最短路径。
广度优先搜索的一般形式如下:
Q.push(初始状态);//将初始状态入队
while(!Q.empty()){Statue u = Q.front();//取出队首Q.pop();//出队for(枚举所有可扩展状态){if(是合法的){Q.push(v);//入队}}
}
对于此问题,先建立一个结构体数组用于存储扩展的结点。先让起点入队,然后在队列取状态逐个扩展。代码如下:
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#define maxn 310
using namespace std;
struct coord{int x,y;//一个结构体存储x,y两个坐标
};
queue<coord> Q;
int ans[maxn][maxn];//记录到每一个点的最小步数,-1表示未访问
int walk[8][2]={{2,1},{1,2},{-1,2},{-2,1},{-2,-1},{-1,-2},{1,-2},{2,-1}};//马能走的8个方向
int main(){int n,m,sx,sy;memset(ans,-1,sizeof(ans));cin>>n>>m>>sx>>sy;coord tmp={sx,sy};//使起点入队扩展Q.push(tmp);ans[sx][sy]=0;while(!Q.empty()){coord u=Q.front();//拿出队首以扩展int ux=u.x,uy=u.y;Q.pop();for(int k=0;k<8;k++){int x=ux+walk[k][0],y=uy+walk[k][1];int d=ans[ux][uy];if(x<1||x>n||y<1||y>m||ans[x][y]!=-1){continue;}ans[x][y]=d+1;//记录答案,是上一个点多走一步的结果coord tmp={x,y};Q.push(tmp);} } for(int i=1;i<=n;i++){for(int j=1;j<=m;j++){printf("%-5d",ans[i][j]);//-号靠左对齐}cout<<endl;}return 0;
}