人生第一道宽搜题 knight move

描述:给你一个8*8的棋盘,骑士的开始位置,结束位置,让你求得骑士从开始位置开始揍到结束位置需要最小的步数是多少?(注意,骑士走日字)
输入:输入包含多组数据,每一行都是一组开始位置和结束位置,位置由两个字符组成,一个是小写字母(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;
}




























  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值