输入:输入包含多组数据,每一行都是一组开始位置和结束位置,位置由两个字符组成,一个是小写字母(a-h),一个是数字(1-8),起始位置结束位置由一个空格隔开.
输出:输出从起始位置到结束位置,骑士所要走过的最小的步数.按照样例的格式来。
输入样例:
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.
这是人生第一道宽搜题,我做的非常辛苦,也很有纪念意义,特此发出来。
首先,何为宽搜?宽搜,也叫广度优先搜索,和深度优先搜索一口气搜到底不同,宽搜颇有些“浪漫情怀”。一点一点,不紧不慢,把一个节点的子节点全部搜索完后,再慢慢的走向下一个节点,正是大将风度。宽搜用到了队列的数据结构。相信很多人和我一样,之前对队列只是了解了定义,什么“先进先出”,却完全没有应用过。宽搜,正是运用队列的一次好机会。
首先说原理:head存储父节点,然后不断的搜索他的子节点,然后压入队列。在这个父节点的所有子节点全部扫描完后,就把他抛弃掉(head++),寻找下一个节点(也就是上一个父节点的子节点)的子节点。同时,为了保证不重复和不溢出,需要判断是否到过和是否越界。
听起来很简单,对吧?但是我在编程序的时候,遇到了各种各样的问题,可以说是上演了“程序员常犯的一百个错误集合”。这里,把他们罗列一下,即警醒自己,也提醒来参观我博客的童鞋(如果有?)
1.变量名冲突:这次很奇葩,取了x1,和math.h头文件冲突了。我天真的认为不引用头文件就好了,但是oj居然自动引用!多谢卿爷指出,这算是个小bug.
2.字符串溢出:一位学长曾真心的教导我:所有数组不要开大,这样debug容易些。我深刻的理解了他的话并应用到生活中,只是一不小心开小了。一定要记住:字符串要多开一位来存储“ \0"!!!!!
3.数组溢出:这次的溢出非常诡异,是我用数据去尝试才试出来的。一般来说,我们都习惯用0为首项,但有时题目要求或是我们自己转化都会以1为首项,这时要特别注意。
4.判断是否越界:这个函数,我本以为很简单,结果却掉进了两个坑。第一个坑,是3的数组越界导致判断条件错了;第二个坑,是我一开始把判断条件改成了”x1x2y1y2"组成的举行,答案当然爆炸。这个惨痛的故事告诉我们,写任何算法,千万不能想当然,一定要三思而后行。
5.入队列过程的step操作:这个我一共错了两次,根本原因是对整个宽搜算法的不理解。当然,step数组全部初始化为0,第一次我写的是入队后step++,第二次写的更奇葩,是step[x][y]=1+step[yuansu[tail-1].x][yuansu[tail-1].y](就是前一个搜索到的节点的step)。出现这些错误都是因为我对算法一知半解,一个父节点的所有子节点的step都应该是父节点加一,只要理解了这一点就好做了。
6.入队过程中的head++操作:一开始居然没有head++!这个还是因为对算法没有透彻理解,加上头晕。
7入队过程中,8个方向的尝试操作:这个bug可以说是这个程序的核心bug。我一开始没用新的变量xx,yy,x,y,只是把x1加来加去,最后一团糟。这里也不想说自己是怎么错的,就说一下正确思路和要注意的几点:(1)x,y是非必要的,他们的作用是记录head节点的坐标。但是用了xy表示后更加显明(在函数push中也用到了)。
(2)xx yy是尝试之后的节点,每次走完又重新赋值。
8.初始化问题:一开始我把step都初始化为-1,为的是表明那些到不了的节点。但一来这样程序的结果都小了一很麻烦,二来题目不会出现这样的情况,就全部赋值为0了。
下面是代码
#include<stdio.h>
#include<iso646.h>
#include<limits.h>
#include<algorithm>
#include<string.h>
#include<ctype.h>
using namespace std;
const int dx[8]={1,2,2,1,-1,-2,-2,-1};
const int dy[8]={-2,-1,1,2,2,1,-1,-2};
struct myk
{
int x;
int y;
};
myk yuansu[64];
int x,y,x11,y11,x22,y22,step[9][9],visit[9][9];
int head,tail,k,xx,yy;
char tempweizhi1[3],tempweizhi2[3];
int converse(char input)
{
int temp;
temp=(int)input-96;
return(temp);
}
int panduan(int x,int y)
{
if((x>0) and (x<=8) and (y>0) and (y<=8))
return 1;
else return 0;
}
void initialization(void)
{
x11=converse(tempweizhi1[0]);
y11=tempweizhi1[1]-48;
x22=converse(tempweizhi2[0]);
y22=tempweizhi2[1]-48;
}
void push(int m,int n)
{
tail++;
yuansu[tail].x=m;
yuansu[tail].y=n;
visit[m][n]=1;
step[m][n]=1+step[x][y];
}
void bfs()
{
while(head<=tail)
{
x=yuansu[head].x;
y=yuansu[head].y;
for(k=0;k<8;k++)
{
xx=x+dx[k];
yy=y+dy[k];
if((panduan(xx,yy)==0)or(visit[xx][yy]==1))continue;
push(xx,yy);
if((xx==x22) and (yy==y22))
return ;
}
head++;
}
}
void shuchu(int n)
{
printf("To get from %s to %s takes %d knight moves.\n",tempweizhi1,tempweizhi2,n);
}
int main(void)
{
while(scanf("%s%s",tempweizhi1,tempweizhi2)!=EOF)
{
initialization();
memset(visit,0,sizeof(visit));
memset(step,0,sizeof(step));
head=tail=0;
yuansu[0].x=x11;
yuansu[0].y=y11;
step[x11][y11]=0;
visit[x11][y11]=1;
bfs();
shuchu(step[x22][y22]);
}
return 0;
}