前一段时间学BFS(宽度优先搜索)最短路的时候,紫书上那个题感觉太复杂了,debug了几天。。。还好最后AC了。
今天发现一个简单的题,而且还觉得挺有意思的,用这个题来学BFS最短路我觉得更合适。这道题题意简单,输入输出也简单,所以代码较短。
题目链接:https://vjudge.net/problem/UVA-439
题目内容:
分析:
第一次看到用bfs求最短路的代码感觉很神奇,竟然还可以这样做。在没有学bfs之前,我都是用dfs遍历所有路找出最短的(超时难免了)。bfs可以用队列实现,要做的就是把当前所在节点的所有下一个节点入列,这样就保证了从队列读取出来的节点都是第n步或者n+1步了,直到发现终点为止,这条路就是最短路。
实现这个思路有几个巧妙的地方,就是该怎么找第n+1个节点。在这道题中,下一个节点可能有8个,用循环可以构造出这8个节点出来(详情见代码)。当然8个节点并不是都可以,超出棋盘的去掉,已经入过列的节点去掉。
还有个问题就是怎么算走了多少步。我把这个数据存在一个8*8数组中,每个节点一定有唯一的步数,并且还顺便把这个数组用来判断一个节点是否走过。
实现代码:
其中的vis数组很关键,构造下一个节点代码部分较巧妙。
#include<cstdio>
#include<queue>
#include<cstring>
#include<cstdlib>
struct Point
{
Point(int r,int c):r(r),c(c) {}
int r,c;
};
char s1[3],s2[3];
int vis[8][8],begin_r,begin_c,end_r,end_c;
int bfs()
{
memset(vis,0,sizeof(vis));
vis[begin_r][begin_c]=1;
std::queue<Point> q;
Point p(begin_r,begin_c);
q.push(p);
while(!q.empty())
{
p=q.front();
q.pop();
if(p.r==end_r&&p.c==end_c)
break;
for(int i=-2; i<3; ++i)
for(int j=-2; j<3; ++j)
if(i&&j&&abs(i)!=abs(j)&&p.r+i>-1&&p.r+i<8&&
p.c+j>-1&&p.c+j<8&&!vis[p.r+i][p.c+j])
{
vis[p.r+i][p.c+j]=vis[p.r][p.c]+1;
q.push(Point(p.r+i,p.c+j));
}
}
return vis[p.r][p.c]-1;
}
int main()
{
while(scanf("%s",s1)==1)
{
begin_r=s1[0]-'a';
begin_c=s1[1]-'1';
scanf("%s",s2);
end_r=s2[0]-'a';
end_c=s2[1]-'1';
printf("To get from %s to %s takes %d knight moves.\n",s1,s2,bfs());
}
return 0;
}