zoj - 1091 - Knight Moves(广度优先法)

这个问题的难处,对我而言在于计步数,开始时想在for(i = 0; i < 8; i++)后来个cnt++计步数,事实证明,那是错误的,因为这样的话每一层的每个元素自己往8个方向移动后,都有个cnt++,而我们每层只应使cnt自加一次就够,于是,将每层最右边的结点保存下来,判断是每层的最右结点再加1。另一个问题是队列的清零问题,没的话,上一组测试数据将影响下一组测试数据。微笑

#include <iostream>
#include <string.h>
#include <queue>

using namespace std;

typedef struct Tdata        //定义结点数据类型
{
    int x;
    int y;
}data;

int s[8][8];        //结点表:a1 对应 s[0][0],a8 对应 s[0][7]
int vis[8][8];      //状态标记,0为未访问过,1为访问过
int cnt;        //步数计数器

int dx[] = {-1, -2, -2, -1, 1, 2,  2,  1};      //与dy一起组成移动间距
int dy[] = {-2, -1,  1,  2, 2, 1, -1, -2};      //与dx一起组成移动间距

queue<data> qu;     //广度优先遍历中用的队列

int bfs(data a, data b)     //a为起始点,b为目标点
{
    int i;
    if(a.x == b.x && a.y == b.y)        //如果起始点已是目标点,返回步数
        return cnt;

    vis[a.x][a.y] = 1;      //将起始点标记为已访问
    qu.push(a);     //入列
    data rear = a, right;      //rear为应该使步数+1时,正在遍历的结点, right用来保存每层遍历最右边的结点
    while(!qu.empty())
    {
        data temp = qu.front();     //取队头元素
        qu.pop();       //出列

        for(i = 0; i < 8; i++)      //对8个方向进行遍历
        {
            data newnode;       //朝某个方向去时的新结点
            newnode.x = temp.x + dx[i];
            newnode.y = temp.y + dy[i];

            if(newnode.x == b.x && newnode.y == b.y)        //若已到达目标结点,返回步数
                return cnt+1;

            //否则,判断移动有没有出界,是否已经遍历过
            if(newnode.x >= 0 && newnode.x < 8 && newnode.y >= 0 && newnode.y < 8 && vis[newnode.x][newnode.y] == 0)
            {
                qu.push(newnode);       //入列
                right = newnode;      //保存结点,只为了最后的每层最右边的那个点
                vis[newnode.x][newnode.y] = 1;      //修改其访问状态
            }
        }
        if(temp.x == rear.x && temp.y == rear.y)        //当正在访问的结点是所在层的最右结点时,步数+1
        {
            cnt++;
            rear = right;       //将新一层的最右结点存起来
        }
    }
    return -1;      //无法到达目标结点时,返回-1,虽然这种情况不会出现
}

int main()
{

    string a, b;
    data begin, end;
    while(cin>>a>>b)
    {

        memset(vis, 0, sizeof(vis));        //令状态数组的初始值为0,即未访问过
        begin.x = a[0] - 'a';       //转换
        begin.y = a[1] - '0' - 1;
        end.x = b[0] - 'a';
        end.y = b[1] - '0' - 1;

        cnt = 0;        //步数清零
        cout<<"To get from "<<a<<" to "<<b<<" takes "<<bfs(begin, end)<<" knight moves."<<endl;

        while(!qu.empty())      //队列清空,这一步很重要,否则可能会使上次在qu中遗留下来的结点干扰现在的结果
        {
            qu.pop();
        }
    }
    return 0;
}


 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值