看了黄煜廉的老师的“2012 ACM 图模型与搜索算法”pdf文件,学习了一下广度遍历算法。看到pdf里面的一道例题,就是hdu1372,名为Knight Moves。然后就开始蒙头蒙脑地敲了。
题目意思是有一个区域,可以模拟为棋盘。Knight可以模拟为象棋中的“马”,它只走“日”字步。所以Knight最多可以有八个方向走,除了边界。这个模拟的棋盘横竖坐标均有八个,坐标x,y分别用(a到h,1到8表示)即是一个8*8的方格。给Knight(骑士)指定一个初始位置和结束位置,要求出它从初始位置到结束位置的最小步数。例子如下:
e2 e4 a1 b2 b2 c3 a1 h8 a1 h7 h8 a1 b1 c3 f6 f6
To get from e2 to e4 takes 2 knight moves. To get from a1 to b2 takes 4 knight moves. To get from b2 to c3 takes 2 knight moves. To get from a1 to h8 takes 6 knight moves. To get from a1 to h7 takes 5 knight moves. To get from h8 to a1 takes 6 knight moves. To get from b1 to c3 takes 1 knight moves. To get from f6 to f6 takes 0 knight moves.
就是普通的广度遍历即可实现,保存步数就用结构体在保存横纵坐标时一起保存即可。代码如下:
#include <iostream>
#include <string>
#include <queue>
using namespace std;
int map[10][10];
struct Node
{
int x, y;
int step;
};
int loop[8][2] = {-1,-2,1,-2,2,-1,2,1,1,2,-1,2,-2,1,-2,-1};
int main()
{
string t1, t2;
while(cin>>t1>>t2)
{
memset(map,0,sizeof(map));
int flag = 0; //找到后用于标记循环结束
Node temp1;
int endx,endy; //保存终点方格坐标
temp1.x = t1[0] - 'a';
temp1.y = t1[1] - '1';
temp1.step = 0;
map[temp1.x][temp1.y] = 1;
queue<Node> q;
q.push(temp1);
endx = t2[0] - 'a';
endy = t2[1] - '1';
while(!q.empty())
{
Node vet = q.front();
if (vet.x==endx && vet.y==endy)
{
cout<<"To get from "<<t1<<" to "<<t2<<" takes "<<vet.step<<" knight moves."<<endl;
}
q.pop();
for (int i = 0; i < 8; i++)
{
Node next;
next.x = vet.x + loop[i][0]; //用数组loop计算出八个方向
next.y = vet.y + loop[i][1];
if (next.x < 0 || next.x > 7 || next.y < 0 || next.y > 7 || map[next.x][next.y]==1)continue;
next.step = vet.step + 1;
if (next.x==endx && next.y==endy)
{
cout<<"To get from "<<t1<<" to "<<t2<<" takes "<<next.step<<" knight moves."<<endl;
flag = 1;
}
if(flag==1)break;
map[next.x][next.y] = 1;
q.push(next);
}
if(flag==1)break;
}
}
return 0;
}
中间的判断边界以及for循环还可以分别用函数独立出来,这样可以省去一个flag变量。
希望有兴趣的朋友可以交流一下。在下新手,望多指教,谢谢。