马踏棋盘
【问题描述】
将马随机放在国际象棋的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;
}