骑士游历问题(马踏棋盘)解析(c++)

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

解题思路:
这是一道经典的遍历问题(DFS),由于题目要求遍历全部,那么肯定要做标记,因此立马想到DFS深度优先算法。具体思路如下:
①了解国际象棋以及国际象棋骑士的走法

国际象棋和中国象棋,大同小异,毕竟中国象棋是老祖先。国际象棋棋子放在格子中,中国象棋放在点上,且国际象棋有64个格子。国际象棋的骑士和中国象棋的马功能相当,都可以走八个方位。走法是走“日”字,或英文字母大写的“L”形:即先向左(或右)走1格,再向上(或下)走2格;或先向左(或右)走2格,再向上(或下)走1格。与中国象棋的馬不同,国际象棋的马可以跳过路上的其他棋子,不受拐脚的限制。
解题需要我们可以把格子抽象成一个点,那么国际象棋的骑士走法就是一个日字
在这里插入图片描述在这里插入图片描述

②设置标记
初始化数组,让每个元素初始化为0,并且初始化一个记录骑士遍历次数的cal也为0
int cal = 0; //统计走的顺序
//初始化为0
int chress[8][8] =           
{
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0
};
③判断是否超界和是否被访问
bool ifOut(int x, int y)  //判断是否出界
{
	if (x >= 0 && x <= 7 && y >= 0 && y <= 7)
		return false;
	else
		return true;
}
bool ifVisited(int x, int y) //判断是否被访问
{
	if (chress[x][y] != 0)
		return true;
	else
		return false;
}
④递归主体
void dfs(int x,int y)
{	
	if (cal == 64) //如果遍历完则退出棋盘一共64个位置
		return;
	if (!ifVisited(x, y) && !ifOut(x, y)) //如果没有被访问且没有出界 则访问
	{
		cal++;   
		chress[x][y] = cal; //做标记
		dfs(x + 2, y + 1);	//骑士走法有八个方位,故八个 方位都遍历
		dfs(x - 2, y - 1);   //八个递归的顺序可以改,顺序不一样,结果不一样
		dfs(x + 2, y - 1);	
		dfs(x - 2, y + 1);	
		dfs(x - 1, y - 2);  
		dfs(x + 1, y - 2);	
		dfs(x + 1, y + 2);	
		dfs(x - 1, y + 2);  
		return;
	}
	else  //else其中包括已经被访问了,和没有被访问且在界外的
		return;
}
⑤总代码如下(编译器vs2013)
#include"stdafx.h"
#include<iostream>
#include<iomanip>
using namespace std;
int cal = 0; //统计走的顺序
//棋盘初始化为0做标记
int chress[8][8] =           
{
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0
};

bool ifOut(int x, int y)  //判断是否出界
{
	if (x >= 0 && x <= 7 && y >= 0 && y <= 7)
		return false;
	else
		return true;
}
bool ifVisited(int x, int y) //判断是否已经被访问
{
	if (chress[x][y] != 0)
		return true;
	else
		return false;
}
void dfs(int x,int y)
{	
	if (cal == 64) //如果遍历完则退出棋盘一共64个位置
		return;
	if (!ifVisited(x, y) && !ifOut(x, y)) //如果没有被访问且没有出界 则访问
	{
		cal++;   
		chress[x][y] = cal; //做标记
		dfs(x + 2, y + 1);	//骑士走法有八个方位,故八个 方位都遍历
		dfs(x - 2, y - 1);  //八个递归的顺序可以改,顺序不一样,结果不一样 
		dfs(x + 2, y - 1);	
		dfs(x - 2, y + 1);	
		dfs(x - 1, y - 2);  
		dfs(x + 1, y - 2);	
		dfs(x + 1, y + 2);	
		dfs(x - 1, y + 2);  
		return;
	}
	else  //出界了则退出return
		return;



}
int main()
{	
	int x, y;
	cout << "请输入骑士初始的位置:";
	while (1)
	{
		cin >> x >> y;    //输入坐标
		if (x > 7 || x<0 || y> 7 || y < 0)
			cout << "初始位置输入错误请重新输入" << endl;
		else
			break;
	}
	dfs(x,y);
	for (int i = 0; i < 8; i++)  //输出打印测试
	{
		for (int j = 0; j < 8; j++)
			cout << setw(2)<<chress[i][j]<<"  ";
		cout << endl;
	}
	return 0;
}
⑥测试截图:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 26
    点赞
  • 134
    收藏
    觉得还不错? 一键收藏
  • 12
    评论
问题描述:将马随机放在国际象棋的 8X8 棋盘中的某个方格中,马按走棋规则进行移动。要求每个方格上只进入一次,走遍棋盘上全部 64 个方格。编制递归程序,求出马的行走路线 ,并按求出的行走路线,将数字 1,2,…,64 依次填入 8X8 的方阵输出之。测试数据:由读者指定可自行指定一个马的初始位置。实现提示:每次在多个可走位置中选择一个进行试探,其余未曾试探过的可走位置必须用适当结构妥善管理,以备试探失败时的“回溯”悔棋使用。并探讨每次选择位置的“最佳策略”,以减少回溯的次数。 背景介绍: 国际象棋为许多令人着迷的娱乐提供了固定的框架,而这些框架常独立于游戏本身。其中的许多框架都基于骑士奇异的L型移动规则。一个经典的例子是骑士漫游问题。从十八世纪初开始,这个问题就引起了数学家和解密爱好者的注意。简单地说,这个问题要求从棋盘上任一个方格开始按规则移动骑士,使之成功的游历国际象棋棋盘的64个方格,且每个方格都接触且仅接触一次。 可以用一种简便的方法表示问题的一个解,即将数字1,……,64按骑士到达的顺序依次放入棋盘的方格中。 一种非常巧妙的解决骑士漫游地方法由J.C.Warnsdorff于1823年给出。他给出的规则是:骑士总是移向那些具有最少出口数且尚未到达的方格之一。其中出口数是指通向尚未到达方格的出口数量。在进一步的阅读之前,你可以尝试利用Warnsdorff规则手工构造出该问题的一个解。 实习任务: 编写一个程序来获得马踏棋盘骑士漫游问题的一个解。 您的程序需要达到下面的要求: 棋盘的规模是8*8; 对于任意给定的初始化位置进行试验,得到漫游问题的解; 对每次实验,按照棋盘矩阵的方式,打印每个格被行径的顺序编号。 技术提示: 解决这类问题的关键是考虑数据在计算机中的存储表示。可能最自然的表示方法就是把棋盘存储在一个8*8的二维数组board中。以(x,y)为起点时骑士可能进行的八种移动。一般来说,位于(x,y)的骑士可能移动到以下方格之一:(x-2,y+1)、(x-1,y+2)、(x+1,y+2)、(x+2,y+1)、(x+2,y-1)、(x+1,y-2)、(x-1,y-2)、(x-2,y-1)。但请注意,如果(x,y)的位置离某一条边较近,有些可能的移动就会把骑士移到棋盘之外,而这当然是不允许的。骑士的八种可能的移动可以用一个数组MoveOffset方便地表示出来: MoveOffset[0]=(-2,1) MoveOffset[1]=(-1,2) MoveOffset[2]=(1,2) MoveOffset[3]=(2,1) MoveOffset[4]=(2,-1) MoveOffset[5]=(1,-2) MoveOffset[6]=(-1,-2) MoveOffset[7]=(-2,-1) 于是,位于(x,y)的骑士可以移动到(x+MoveOffset[k].x, y+MoveOffset[k].y),其中k是0到7之间的某个整数值,并且新方格必须仍位于棋盘上。
问题描述:将马随机放在国际象棋的 8X8 棋盘中的某个方格中 马按走棋规则进行移动 要求每个方格上只进入一次 走遍棋盘上全部 64 个方格 编制递归程序 求出马的行走路线 并按求出的行走路线 将数字 1 2 … 64 依次填入 8X8 的方阵输出之 测试数据:由读者指定可自行指定一个马的初始位置 实现提示:每次在多个可走位置中选择一个进行试探 其余未曾试探过的可走位置必须用适当结构妥善管理 以备试探失败时的“回溯”悔棋使用 并探讨每次选择位置的“最佳策略” 以减少回溯的次数 背景介绍: 国际象棋为许多令人着迷的娱乐提供了固定的框架 而这些框架常独立于游戏本身 其中的许多框架都基于骑士奇异的L型移动规则 一个经典的例子是骑士漫游问题 从十八世纪初开始 这个问题就引起了数学家和解密爱好者的注意 简单地说 这个问题要求从棋盘上任一个方格开始按规则移动骑士 使之成功的游历国际象棋棋盘的64个方格 且每个方格都接触且仅接触一次 可以用一种简便的方法表示问题的一个解 即将数字1 64按骑士到达的顺序依次放入棋盘的方格中 一种非常巧妙的解决骑士漫游地方法由J C Warnsdorff于1823年给出 他给出的规则是:骑士总是移向那些具有最少出口数且尚未到达的方格之一 其中出口数是指通向尚未到达方格的出口数量 在进一步的阅读之前 你可以尝试利用Warnsdorff规则手工构造出该问题的一个解 实习任务: 编写一个程序来获得马踏棋盘骑士漫游问题的一个解 您的程序需要达到下面的要求: 棋盘的规模是8 8; 对于任意给定的初始化位置进行试验 得到漫游问题的解; 对每次实验 按照棋盘矩阵的方式 打印每个格被行径的顺序编号 技术提示: 解决这类问题的关键是考虑数据在计算机中的存储表示 可能最自然的表示方法就是把棋盘存储在一个8 8的二维数组board中 以 x y 为起点时骑士可能进行的八种移动 一般来说 位于 x y 的骑士可能移动到以下方格之一: x 2 y+1 x 1 y+2 x+1 y+2 x+2 y+1 x+2 y 1 x+1 y 2 x 1 y 2 x 2 y 1 但请注意 如果 x y 的位置离某一条边较近 有些可能的移动就会把骑士移到棋盘之外 而这当然是不允许的 骑士的八种可能的移动可以用一个数组MoveOffset方便地表示出来: MoveOffset[0] 2 1 MoveOffset[1] 1 2 MoveOffset[2] 1 2 MoveOffset[3] 2 1 MoveOffset[4] 2 1 MoveOffset[5] 1 2 MoveOffset[6] 1 2 MoveOffset[7] 2 1 于是 位于 x y 的骑士可以移动到 x+MoveOffset[k] x y+MoveOffset[k] y 其中k是0到7之间的某个整数值 并且新方格必须仍位于棋盘上 扩展需求:可以考虑将结果图形化 b 考察所有初始化的情况 测试是否都能够得到解 ">问题描述:将马随机放在国际象棋的 8X8 棋盘中的某个方格中 马按走棋规则进行移动 要求每个方格上只进入一次 走遍棋盘上全部 64 个方格 编制递归程序 求出马的行走路线 并按求出的行走路线 将数字 1 2 … 64 依 [更多]
骑士游历问题是一个经典的算法问题,其涉及到如何在国际象棋棋盘上使得骑士能够遍历所有格子,每个格子只能经过一次。 解决这个问题的一种方法是通过使用深度优先搜索(DFS)算法。DFS算法是一种递归算法,用于遍历所有可能的路径直至找到目标解。 在C语言中,可以通过二维数组来表示棋盘,使用递归函数来实现DFS算法。首先,需要定义一个8x8的棋盘,初始值为0表示未经过。接着,定义一个骑士可能的移动方式,可以在棋盘上向上、向下、向左、向右以及对角线移动。然后,从棋盘的某个起始位置开始,向下一个可能的位置进行递归搜索,直到找到所有解。 在递归函数中,需要判断当前位置是否有效,即是否在棋盘范围内且未经过。如果有效,将当前位置标记为已经过,并继续探索下一个位置。如果无效,则回溯到上一个位置,并且将当前位置恢复为未经过。 为了保证骑士能够遍历所有格子,可以设置一个计数变量,每遍历一个位置就加一,直到计数值等于棋盘大小。当计数值等于棋盘大小时,表示找到了一种遍历方案,结束程序,并输出结果。 对于骑士游历问题的C语言视频讲解,可以结合图形化界面展示程序运行过程,以便更直观地理解算法的实现过程。视频中可以包括:问题的介绍与背景知识讲解、算法的具体实现方法、程序运行演示以及最终输出结果。同时,可以提供一些优化的思路和实现技巧,例如剪枝、迭代加深等,以提高程序的效率和性能。 通过视频讲解,可以让学习者更加深入地了解骑士游历问题的解决思路,并且能够动手实现相关的算法。同时,视频的交互性也能够方便学习者向讲解者提问或者参与讨论,进一步加深对问题的理解。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值