http://poj.org/problem?id=1915
一道不错的基础广搜题目,记得很久以前接触的搜索,当时只是浅浅的接触了一下,不过很快就忘了,貌似chl也不太熟,以至于之前的几次比赛,一遇到搜索的题目我就了,幸亏我们队还有飘飘。。搜索是图论的基础,一定要学好
背景:神话般的国际象棋玩家Somurolov先生,他声称,他可以把一个骑士从一个位置很快地移动到另一个位置,但其他人却不行。你能打败他吗?
存在的问题:你的任务是编写一个程序来计算骑士达到从另一个位置所要移动的最少步数,这样你才有机会比Somurolov快。也许人们不熟悉的国际象棋,骑士行动可能在如图1所示。
输入:首先在第一个行,输入n,表示有n种的情况。 接下来是n方案。每个方案包括三行。第一行指定一个棋盘边长L(4<=L<= 300)。整个棋盘的尺寸L*L.第二和第三行包含整数对(0,...,L - 1)*(0,...,L - 1)指定骑士开始和结束位置。整数对由一个空白分隔开。
输出:对于每个输入你要计算骑士的行动,有必要从起点移动到终点最少步数的情况。如果起点和终点都是平等的,距离是零。
解题思路:题目其实就是(在满足骑士走法的条件下)求起点到终点的最短路,而广搜是一层一层的搜,这样如果从起点开始,一层一层的扩展,只要到达终点所用的步数就是最少的。
#include<stdio.h>
#include<string.h>
#define N 305
bool m[N][N];
int fx[8][2]= // 方向数组
{{-2,-1},{-1,-2},{1,-2},{2,-1},
{2,1},{1,2},{-1,2},{-2,1}};
struct stu //结点信息
{
int x,y,step;
bool operator ==(stu t) //重载运算符“==”
{
return t.x==x&&t.y==y;
}
}S,T,queue[N*N];//起点,终点,队列
int n; //图的大小
int bfs()
{
int front,end,i;
stu s,t;
front=end=0; //初始化队列
queue[end++]=S; //起点入队
memset(m,false,sizeof(m)); //标记数组初始化
while(front<end) //判断队列是否为空
{
s=queue[front++]; //出队
if(s==T) return s.step; //判断是否到达终点
for(i=0;i<8;i++) //八个方向
{
t.x=s.x+fx[i][0];
t.y=s.y+fx[i][1];
t.step=s.step+1;
if(t.x<0||t.y<0||t.x>=n||t.y>=n) //判断是否出界
continue;
if(m[t.x][t.y]) continue; //判断之前是否已经到达过
queue[end++]=t; //入队
m[t.x][t.y]=true; //标记
}
}
return -1;
}
int main()
{
int p;
scanf("%d",&p);
while(p--)
{
scanf("%d",&n);
scanf("%d%d%d%d",&S.x,&S.y,&T.x,&T.y);
printf("%d\n",bfs());
}
return 0;
}