马踏棋盘

马踏棋盘

【问题描述】

将马随机放在国际象棋的8* 8棋盘Bord[8Ⅱ8]的某个方格中,马按走棋规则进行移动。要求每个方格上只进入一次,走遍棋盘上全部64个方格。

【任务要求】

编制非递归程序,求出马的行走路线 ,并按求出的行走路线,将数字1,2,…,64依次填入一个8* 8的方阵,输出之。
测试数据:由读者指定,可自行指定一个马的初始位置。
实现提示:每次在多个可走位置中选择一个进行试探,其余未曾试探过的可走位置必须用适当结构妥善管理,以备试探失败时的“回溯”(悔棋)使用。

【测试数据】

自行设定,注意边界等特殊情况。

代码

#include<iostream>
#include<algorithm>
#include<stack>
using namespace std;
struct dir{
	int x, y;
};
int n = 64;
dir di[8];
int d[8][2] = { 1,2,   1,-2,   -1,2,   -1,-2,    2,1,    2,-1,     -2,1,    -2,-1 };
int visit[8][8];
struct node {
	int x;
	int y;
	int d = 0;         //用来标记从该结点该跳向第几个临近位置;
	int out_way() {
		int k = 0;
		for (int i = 0; i < 8; i++)
		{
			int X = this->x + di[i].x;
			int Y = this->y + di[i].y;
			if (!(X < 0 || X >= 8 || Y < 0 || Y >= 8 || visit[X][Y]== 1))
				k++;
		}
		return k;
	}
};
stack<node> stac;             //存放结点
node  no;                     //记录当前结点
node map[8][8];
bool cmp(dir a,dir b) {
	//初始化下标
	int m = -1, n = -1;
	//如果下标不符合条件或该位置已访问   最小化m;n;
	if (no.x + a.x < 0 || no.x + a.x >= 8 || no.y + a.y < 0 || no.y + a.y >= 8 || visit[no.x + a.x][no.y + a.y] == 1)
		m = 0;
	if (no.x + b.x < 0 || no.x + b.x >= 8 || no.y + b.y < 0 || no.y + b.y >= 8 || visit[no.x + b.x][no.y + b.y] == 1)
		n = 0;
	//如果下标未被最小化,将m,n初始化为子邻接点出路个数;
	if (m != 0)
		m = map[no.x + a.x][no.y + a.y].out_way();
	if (n != 0)
		n = map[no.x + b.x][no.y + b.y].out_way();
	//ruturn m<n 从小到大排序 (不符合条件的子节点或以访问的排在前面 其他按照出路多少从小大大排序) 
	return m < n;
}
void def() {
	while (stac.size() != 64)
	{
		if (stac.size() == 0)
		{
			cout << "无结果" << endl;
			break;
		}
		//应该访问第几个子邻接点
		int i = map[stac.top().x][stac.top().y].d;                 
		//如果八个邻接点全部访问完  将该结点初始化并出栈 
		if (i >= 8)                                                
		{
			visit[stac.top().x][stac.top().y]= 0;
			map[stac.top().x][stac.top().y].d = 0;
			stac.pop();
			continue;
		}
		//得到当前栈顶结点 排序用
		no = stac.top();      
		sort(di, di + 8,cmp);
		//不符合条件的邻接点 continue;
		int X = stac.top().x + di[i].x;
		int Y = stac.top().y + di[i].y;
		if (X < 0 || X >= 8 || Y < 0 || Y >= 8 || visit[X][Y]== 1)
		{
			map[stac.top().x][stac.top().y].d++;
			continue;
		}
		//入栈前栈顶元素子临界点递进一
		//cout << map[X][Y].x << ' ' << map[X][Y].y << ' '<<stac.size()<<endl;
		map[stac.top().x][stac.top().y].d++;
		//符合条件  入栈
		visit[X][Y]= 1;
		stac.push(map[X][Y]);
	}
}
int main() {
	//将方向二维数组赋值给方向结构体一维数组 
	for (int i = 0; i < 8; i++)
	{
		di[i].x = d[i][0];
		di[i].y = d[i][1];
	}

	int x, y;
	cin >> x >> y;
	//棋盘初始化
	for (int i = 0; i < 8; i++)
		for (int j = 0; j < 8; j++)
		{
			map[i][j].x = i;
			map[i][j].y = j;
		}
	//第一个节点压栈
	visit[x-1][y-1]= 1;
	stac.push(map[x-1][y-1]);

	def();
	//依靠出栈顺序将给新建数组a赋值  输出a;
	int a[8][8];
	while (stac.empty() == 0)
	{
		a[stac.top().x][stac.top().y] = n;
		n--;
		stac.pop();
	}
	for (int i = 0; i < 8; i++)
	{
		for (int j = 0; j < 8; j++)
			cout << a[i][j] << '\t';
		cout << endl;
	}
	system("pause");
	return 0;
}

先来讲一讲这个代码里的结构体

由于这个马踏棋盘如果单纯的用深度优先搜索的话 时间复杂度会非常非常大(888888888*8…(64个八))。这个题很有必要优化 用贪心 在当前八个位置中尽可能选择出路较少的位置走,这样可以避免许多出现死路而要回溯的情况。所以结构体有:必要的位置坐标x,y。当前应该选择的位置(之前会依据出度多少给八个位置从少到多进行排序)。还有个查询位置出度的结构体函数(用于给八个位置自定义排序)

struct node {
	int x;
	int y;
	int d = 0;         //用来标记从该结点该跳向第几个临近位置;
	int out_way() {
		int k = 0;
		for (int i = 0; i < 8; i++)
		{
			int X = this->x + di[i].x;
			int Y = this->y + di[i].y;
			if (!(X < 0 || X >= 8 || Y < 0 || Y >= 8 || visit[X][Y]== 1))
				k++;
		}
		return k;
	}
};

再来看深度优先搜索

看注释吧 没啥解释的

void def() {
	while (stac.size() != 64)
	{
		if (stac.size() == 0)
		{
			cout << "无结果" << endl;
			break;
		}
		//应该访问第几个子邻接点
		int i = map[stac.top().x][stac.top().y].d;                 
		//如果八个邻接点全部访问完  将该结点初始化并出栈 
		if (i >= 8)                                                
		{
			visit[stac.top().x][stac.top().y]= 0;
			map[stac.top().x][stac.top().y].d = 0;
			stac.pop();
			continue;
		}
		//得到当前栈顶结点 排序用
		no = stac.top();      
		sort(di, di + 8,cmp);
		//不符合条件的邻接点 continue;
		int X = stac.top().x + di[i].x;
		int Y = stac.top().y + di[i].y;
		if (X < 0 || X >= 8 || Y < 0 || Y >= 8 || visit[X][Y]== 1)
		{
			map[stac.top().x][stac.top().y].d++;
			continue;
		}
		//入栈前栈顶元素子临界点递进一
		map[stac.top().x][stac.top().y].d++;
		//符合条件  入栈
		visit[X][Y]= 1;
		stac.push(map[X][Y]);
	}
}

主函数

也没啥说的

int main() {
	//将方向二维数组赋值给方向结构体一维数组  方便给方向排序
	for (int i = 0; i < 8; i++)
	{
		di[i].x = d[i][0];
		di[i].y = d[i][1];
	}

	int x, y;
	cin >> x >> y;
	//棋盘初始化
	for (int i = 0; i < 8; i++)
		for (int j = 0; j < 8; j++)
		{
			map[i][j].x = i;
			map[i][j].y = j;
		}
	//第一个节点压栈
	visit[x-1][y-1]= 1;
	stac.push(map[x-1][y-1]);

	def();
	//依靠出栈顺序将给新建数组a赋值  输出a;
	int a[8][8];
	while (stac.empty() == 0)
	{
		a[stac.top().x][stac.top().y] = n;
		n--;
		stac.pop();
	}
	for (int i = 0; i < 8; i++)
	{
		for (int j = 0; j < 8; j++)
			cout << a[i][j] << '\t';
		cout << endl;
	}
	system("pause");
	return 0;
}

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值