题目描述
有一个n*m的棋盘(1<n,m<=400),在某个点上有一个马,要求你计算出马到达棋盘上任意一个点最少要走几步
输入格式
一行四个数据,棋盘的大小和马的坐标
输出格式
一个n*m的矩阵,代表马到达某个点最少要走几步(左对齐,宽5格,不能到达则输出-1)
输入输出样例
输入
3 3 1 1
输出
0 3 2
3 -1 1
2 1 4
题意:
在一个二维数组中,马到每一个坐标所需要的步数是多少,若无法到达,则为-1。
题解:
首先要确定马可以走8个方向(根据马走“日”来确定),然后就用搜索的方法,这里讲解两种方法:BFS和DFS。
根据这个图的逻辑来写出代码
BFS的AC代码
#include<bits/stdc++.h>
using namespace std;
int n, m, sx, sy; //sx,xy为初始马的坐标
int dx[8] = {1, 1, -1, -1, 2, 2, -2, -2};
int dy[8] = {2, -2, 2, -2, 1, -1, 1, -1}; //dx,,dy是马能走的8个方向
int ans[500][500]; //计步数
bool vis[500][500]; //做标记
int xx, yy; //新的马的坐标
struct xy
{
int x, y;
}node, top;
queue<xy> q;
void bfs(int x, int y, int step)
{
ans[x][y] = step;
vis[x][y] = false;
node.x = x;
node.y = y;
q.push(node); //将起点放入队列
while(!q.empty())
{
top = q.front(); //取出队列
q.pop();
for(int i = 0; i < 8; i++)
{
xx = top.x + dx[i]; //新的坐标
yy = top.y + dy[i];
if(xx > 0 && xx <= n && yy > 0 && yy <= m) //判断是否在边界范围内
{
if(vis[xx][yy]) //判断是否来过
{
node.x = xx;
node.y = yy;
q.push(node); //把新的坐标放入队列
ans[xx][yy] = ans[top.x][top.y] + 1; //记录到达的步数
vis[xx][yy] = false; //标记来过
}
}
}
}
}
int main()
{
cin>>n>>m>>sx>>sy;
memset(ans, -1, sizeof(ans));
memset(vis, true, sizeof(vis));
bfs(sx, sy, 0);
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= m; j++)
{
printf("%-5d",ans[i][j]);
}
cout<<endl;
}
}
DFS的方法:
根据这张图来写AC代码:
#include<bits/stdc++.h>
using namespace std;
int n, m;
int sx, sy;
int dx[8] = {1, 1, -1, -1, 2, 2, -2, -2};
int dy[8] = {2, -2, 2, -2, 1, -1, 1, -1};
int ans[500][500]; //计步数
int xx, yy; //新的坐标
void dfs(int x, int y, int step)
{
ans[x][y] = step;
if(step > 400) //简单的剪枝,因为题目给出1<n,m<=400,
return ; //所以如果马从(1,1)到(400,400)
//最多也不超过400
//(就看每次x或y走一格,一直走到400格)
for(int i = 0; i < 8; i++)
{
xx = dx[i] + x;
yy = dy[i] + y; //新的坐标
if(xx > 0 && xx <= n && yy > 0 && yy <= m) //判断是否在边界内
{
if(ans[xx][yy] == -1 || ans[xx][yy] > step + 1)
{ /*第一个是判断是否来过该坐标,第二个是判断如果这个坐标又来到了,
那与之前的步数相比,是否这次的步数要少,若少,则取这次的步数;反之,则不取*/
dfs(xx, yy, step + 1); //这里就不需要进行回溯操作了
}
}
}
}
int main()
{
memset(ans, -1, sizeof(ans));
while(cin>>n>>m>>sx>>sy)
{
dfs(sx, sy, 0);
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= m; j++)
{
printf("%-5d",ans[i][j]);
}
cout<<endl;
}
}
}
总结一下
bfs和dfs的最大区别是,dfs是一条路走到底,不撞南墙不回头;而bfs则是一层一层的搜。dfs主要的实现方法就是递归;bfs则是用队列来实现。写题时,需准确的判断是使用那种解题方法,因为对于不同的题,这两种的运行时间是不同的,而这可能也是题目过不了的原因。