【数据结构实验】栈与马踏棋盘问题(递归 + 非递归版本)

一、实验内容

【问题描述】设计一个国际象棋的马踏遍棋盘的演示程序。
【基本要求】将马随机放在国际象棋的8×8棋盘Board[0~7][0~7]的某个方格中,马按走棋规则进行移动。要求每个方格只进入一次,走遍棋盘上全部64个方格。编制程序,求出马的行走路线,并按求出的行走路线,将数字1,2,…,64依次填入一个8×8的方阵,输出之。
【测试数据】自行指定马的初始位置。
【实现提示】
马在棋盘上走“日”字型,比如初始马在第2行第3列,可行走的八个位置见下图。

二、实验目的

1.熟悉掌握栈的基本操作。
2.培养运用栈解决问题的能力。

三、概要设计

(文字性地说明解决问题的具体方法和步骤)

递归版本:

每次循环会随机生成马的初始位置,然后调用递归函数,执行完毕后输出。
递归函数的写法:
设当前尝试填写的坐标为<x, y>。首先将递归的终止条件写入最前:
当填写的编号达到64时,返回true,表示填入完成,每层递归都会在深层递归返回true后也返回true,层层返回后函数终止。
如果当前坐标已经走到棋盘外,就要校正,使得坐标总在棋盘内。
然后尝试填入,如果该格已被填入,返回false,表示尝试失败。否则,填入该格,编号id递增。
接下来递归填写周围8格,每个格的坐标是<x±2,y±1>或<x±1,y±2>。
如果周围8个格都返回false(无论是从深层开始层层返回的还是仅深一层尝试就返回的),代表该填写方式无法走完全部棋盘,该解不符合要求,撤销本格填写,返回false,向浅一层递归报告失败。

非递归版本:

建立栈s和t,分别用于保存已经填入的位置的坐标和已经枚举的下一个填写位置的坐标的数量。当整个棋盘都被填完,即栈s的大小达到64,填写结束。程序是循环运行的,如果要退出,直接按右上角的“×”关闭。每次循环会随机生成马的初始位置,然后重复执行以下算法,直到栈s的大小为64:
尝试写入当前位置,如果已写满棋盘返回-1,写入成功返回1,不成功返回0。
当返回-1时,结束填写。
当返回1时,将已填写的位置压入栈s,填写下一个格。设当前坐标为<x, y>,下一个格的坐标总是为<x±2,y±1>或<x±1,y±2>。如果刚才返回1,那么重新列举这8个位置中的一个,栈t压入0。枚举周围8格时,要先修正枚举的位置,因为直接做x,y±1或2的运算时可能会使x或y小于0或大于7到达棋盘外,此时就需要把坐标移回棋盘内。
当返回0时,尝试枚举下一个可填入的位置同时要把栈t的顶端的值递增。当全部8个位置都枚举完毕且无法继续填下去(全部返回0),需要从栈s删除栈顶的坐标,并同步弹出栈t的栈顶元素,因为如果填了这个位置,接下来就无解。删除坐标后,已经枚举的格数要改成当前t的栈顶的值,因为要从上一个填完的格子继续枚举周围8个可填坐标,而这8格里有些格子可能已经被填写了。
填写完毕后,输出棋盘的每个格的编号。

四、参考代码

#include<cstdio>
#include<algorithm>
#include<random>
#include<chrono>
#include<stack>
#include<map>
#pragma warning(disable:4996)
int b[8][8], id, did; std::uniform_int_distribution<int> u(0, 7); std::default_random_engine d; 
std::stack<std::pair<int, int>> s; std::stack<int> t; std::pair<int, int> p, q;
bool fill(int x, int y) {
   
	if (id >= 64)return true;
	if (x < 0)x += 8; else if (x > 7)x -= 8;
	if (y < 0)y += 8; else if (y > 
  • 3
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值