骑士游历问题——程序设计艺术与方法实验二 搜索算法的实现

骑士游历问题——程序设计艺术与方法实验二 搜索算法的实现

骑士游历问题: 在国际棋盘上使一个骑士遍历所有的格子一遍且仅一遍,对于任意给定的顶点,输出一条符合上述要求的路径。

分析:
国际象棋以及国际象棋骑士的走法
国际象棋棋子放在格子中。国际象棋的骑士可以走八个方位。走法是走“日”字,或英文字母大写的“L”形:即先向左(或右)走1格,再向上(或下)走2格;或先向左(或右)走2格,再向上(或下)走1格。国际象棋的马可以跳过路上的其他棋子,不受拐脚的限制。
解题需要我们可以把格子抽象成一个点,那么国际象棋的骑士走法就是一个日字。

在这里插入图片描述

定义二位数组作为棋盘,初始化为0;
DFS算法遍历,判断是否已被访问或是否超界,若非法则回溯。
所有点被访问时输出路径。

代码:

#include <iostream>
#include <vector>
#include <algorithm>
#include <iomanip>
//题目要求:这里是以国际象棋的棋盘8 * 8的方格棋盘,
//现在将“马”放在任意指定的方格的方格中,按照马走棋盘的规则将马进行移动。
//并且要求每个方格只能进入一次,最终让“马”走遍64个方格。
//编写代码: 要求使用1~64来标注马移动的路径。
/*
骑士游历问题的解决步骤和思路
选择当前位置,记录还可以继续往下走的位置,如果可以走就继续往下走,不可以就回溯。
如何走,是根据我们的决策来的,我们的决策是会影响最后的效率
1.创建棋盘chessBoard,是一个二维数组
2.将当前位置设置为已访问,然后根据当前位置,计算马儿还能走哪些位置,
  并放到一个容器中,最多有八个位置,每走一步,step+1
3.遍历所有位置,看看哪个可以走通,如果走通,就继续,走不通就回溯
4.判断马儿是否完成遍历任务,使用step和应该走的步数比较
*/
using namespace std;
const int MAX_SIZE = 8;//八行八列的棋盘
int step = 0;//遍历的次数
int chessBoard[MAX_SIZE][MAX_SIZE] = { 0 }; //标记是否走过,已走过的点设为到当前的步数
const int dir[8][2] = { {-1, 2}, {-2, 1}, {-2, -1}, {-1, -2},
                        {1, 2}, {2, 1}, {2, -1}, {1, -2} };//定义可以走的八个方向
typedef struct p
{
    int x, y;
}Point;//点
vector<Point> points;//存储走过的点

bool isInChess(const Point& pos)
{
    return 0 <= pos.x && pos.x < MAX_SIZE && 0 <= pos.y && pos.y < MAX_SIZE;
}//判断当前走的点是否越界

bool ifVisited(const Point& pos)
{
    return chessBoard[pos.x][pos.y] != 0;
}
void dfs(const Point& now)
{
    if (step == 64) 
        return ;//所有点均已遍历 结束
    if (isInChess(now) && !ifVisited(now))
    {
        step++;
        points.push_back(now);//当前点进入容器
        chessBoard[now.x][now.y] = step;
        for (int ind = 0; ind < 8; ind++) {//对八个方向进行遍历
            Point next = now;
            next.x += dir[ind][0];
            next.y += dir[ind][1];  //下一个点的坐标
            dfs(next);
        }
        return;
    }
    else
        return;
}

int main()
{
    int x, y;
    cout << "请输入骑士起始坐标:";
    while (1)
    {
        cin >> x >> y;
        if (x <= 0 && x > MAX_SIZE &&  y <= 0 && y > MAX_SIZE)
            cout << "初始位置输入错误请重新输入" << endl;
        else
            break;
    }
    Point point;
    point.x = x-1;
    point.y = y-1;
    dfs(point);
    for (int i = 0; i < 8; i++)
    {
        for (int j = 0; j < 8; j++)
            cout << setw(2) << chessBoard[i][j] << "  ";
        cout << endl;
    }
    vector<Point>::iterator it = points.begin();
    int i = 0;
    while (it != points.end())
    {
        i++;
        cout << "第" << i << "步 : ";
        cout << "(" << it->x << "," << it->y << ")" << endl;
        it++;
    }
    return 0;
}

运行结果:
在这里插入图片描述

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值