急救 马的遍历问题

lidinghui05 2007-06-18 09:26:51
设计程序完成如下要求:在中国象棋棋盘上,对任意位置上放置的一个马,均能选择一个合适的路线,使得该棋子能按象棋的规划不重复地走过棋上的每一个位置。要求:(1)依次输出所有走过的各位置的坐标。(2)最好能画出棋盘的图形形式,并在其上动态地标注行走的过程。(3)程序能方便地移植到其他规格的棋盘上。
...全文
734 22 打赏 收藏 转发到动态 举报
写回复
用AI写文章
22 条回复
切换为时间正序
请发表友善的回复…
发表回复
BuleRiver 2008-11-20
  • 打赏
  • 举报
回复
递归
lidinghui05 2008-11-17
  • 打赏
  • 举报
回复
//判断"当前点"是否已经访问过
bool IsVisted(void)
{
if (chess[x][y].value == 1)
{
return 1; //已被访问过
}
else
{
return 0; //未被访问过
}
}

//是否已经遍历完
bool IsFinish(void)
{
if (step == (m*n-1))
{
return 1;
}
else
{
return 0;
}
}

//打印路径栈
void printpath(void)
{
/*
point a[m*n]; //用来存放栈
for (int i=0;i<m*n;i++)
{
a[i] = *(--path.top);
}
for (int j=(m*n-1);j>=0;j++)
{
cout<<"("<<a[j].x<<","<<a[j].y<<")"<<" ";
if (j % n == 0)
{
cout<<endl;
}
}
*/
while (path.base != path.top)
{
cout<<(--path.top)->x<<" "<<(--path.top)->y<<" ";
}
int x;
cin>>x;
}

void push()
{
//压栈
(*(path.top++)).x = chess[x][y].x;
(*(path.top++)).y = chess[x][y].y;
(*(path.top++)).di = chess[x][y].di;
(*(path.top++)).value = chess[x][y].value;
}


//主函数
int main(int argc, char* argv[])
{
//确定起始点
cout<<"请输入起始位置(x,y):"<<endl;
cin>>x>>y;

//初始化棋盘,棋盘由"点"组成
for (int i=0;i<m;i++)
{
for (int j=0;j<n;j++)
{
chess[i][j].x = i;
chess[i][j].y = j;
chess[i][j].value = 0;
chess[i][j].di = 1;
}
}

initpath(); //初始化路径栈

do
{
if (!IsOut()) //下一步没有出界
{
forward(); //向前走一步
if (!IsVisted()) //未被访问
{
chess[x][y].value = 1;
push();
step++;
}
else //已被访问
{
push();
backward();
}
}
else //下一步出界了
{
chess[x][y].di++; //改变方向
}

if (chess[x][y].di>8)
{
if (IsFinish())
{
break; //如果已经全部遍历,则退出
}
else
{
backward(); //无路可走,并且并没走完
}
}

}while(!StackEmpty()); //栈非空

printpath(); //打印路径栈

delete []path.base;

return 0;
}
//---------------------------------------------------------------------------
lidinghui05 2008-11-17
  • 打赏
  • 举报
回复
//---------------------------------------------------------------------------
#include <vcl.h>
#include <iostream.h>
#pragma hdrstop
//---------------------------------------------------------------------------
#pragma argsused
//全局变量
const int m = 8; //棋盘的列
const int n = 8; //棋盘的行
int x,y; //x,y坐标
int step = 0; //步骤

//结构:point
struct point
{
int x; //x坐标
int y; //y坐标
short di; //方向度:1~8表示8个不同的跳跃方向
bool value; //值:1表示已访问,0表示未访问
}chess[m][n];

//栈:path
//马跳过的路径用栈来表示
struct path
{
point *base;
point *top;
}path;

//初始化路径栈
void initpath(void)
{
path.base = new point[m*n];

if (!path.base)
{
exit(1); //分配不成功,则退出
}

path.top = path.base;
}

//后退一步
void backward(void)
{
/*在当前点已经被访问过的情况下,后退一步*/
path.top--; //删除栈顶元素

chess[x][y].x = (*(path.top-1)).x; //返回新的栈顶元素
chess[x][y].y = (*(path.top-1)).y;
chess[x][y].di = (*(path.top-1)).di;
chess[x][y].value = (*(path.top-1)).value;

chess[x][y].di++;
}

//前进一步
void forward(void)
{
switch(chess[x][y].di)
{
//根据方向度,选择不同的跳跃方式
case 1:
chess[x][y].x = chess[x][y].x + 2;
chess[x][y].y = chess[x][y].y + 1;
break;
case 2:
chess[x][y].x = chess[x][y].x + 1;
chess[x][y].y = chess[x][y].y + 2;
break;
case 3:
chess[x][y].x = chess[x][y].x - 1;
chess[x][y].y = chess[x][y].y + 2;
break;
case 4:
chess[x][y].x = chess[x][y].x - 2;
chess[x][y].y = chess[x][y].y + 1;
break;
case 5:
chess[x][y].x = chess[x][y].x - 2;
chess[x][y].y = chess[x][y].y - 1;
break;
case 6:
chess[x][y].x = chess[x][y].x - 1;
chess[x][y].y = chess[x][y].y - 2;
break;
case 7:
chess[x][y].x = chess[x][y].x + 1;
chess[x][y].y = chess[x][y].y - 2;
break;
case 8:
chess[x][y].x = chess[x][y].x + 2;
chess[x][y].y = chess[x][y].y - 1;
break;
default:
break;
}
}

//判断path栈是否为空
bool StackEmpty()
{
if (path.top == path.base)
{
return 1; //空
}
else
{
return 0; //非空
}
}

//判断下一步是否会出界
bool IsOut(void)
{
switch(chess[x][y].di)
{
case 1:
if ((chess[x][y].x+2)>=m||(chess[x][y].y+1)>=n)
{
return 1;
}
else
{
return 0;
}
case 2:
if ((chess[x][y].x+1)>=m||(chess[x][y].y+2)>=n)
{
return 1;
}
else
{
return 0;
}
case 3:
if ((chess[x][y].x-1)<0||(chess[x][y].y+2)>=n)
{
return 1;
}
else
{
return 0;
}
case 4:
if ((chess[x][y].x-2)<0||(chess[x][y].y+1)>=n)
{
return 1;
}
else
{
return 0;
}
case 5:
if ((chess[x][y].x-2)<0||(chess[x][y].y-1)<0)
{
return 1;
}
else
{
return 0;
}
case 6:
if ((chess[x][y].x-1)<0||(chess[x][y].y-2)<0)
{
return 1;
}
else
{
return 0;
}
case 7:
if ((chess[x][y].x+1)>=m||(chess[x][y].y-2)<0)
{
return 1;
}
else
{
return 0;
}
case 8:
if ((chess[x][y].x+2)>=m||(chess[x][y].y-1)<0)
{
return 1;
}
else
{
return 0;
}
default:
break;
}
return 1;
}
lidinghui05 2008-11-17
  • 打赏
  • 举报
回复
#1 "五位马表",终结马的走法

以前介绍过折叠位棋盘的技术,由于位棋盘的速度问题,而暂时冷落下来,真正使用折叠位棋盘的人不多。下面介绍一种技术,从位棋盘的思想演变而来,但不需要在位棋盘上实现。为了使用方便将其称为“5位马表”。(名称如有更好,欢迎提供)
首先,预置一个如下的数组(如下图,贴上来没有表格,不好看),棋盘的坐标可以从下到上,也可以从左到右,但是里面的值一定要从下到上,以前讲折叠位棋盘时,共需要8位,有3位是冗余的,并且棋盘的坐标要求从下到上,现在没有这个要求,并且只要求5位,没有冗余,这样会产生冲突吗?先了解一下构成该表的原则:任意一个格子的四周不能有相同的值,加上格子自身需要一个值,就是说最少需要5个不同的值,将4个不同的值精心排列在周围,使其不发生冲突,就得到下表(你也可以自己排列下表)。
我们将表中为数值1的定义为1号格子,为2的定义为2号格子,为4的定义为4号格子,等等。观察表可知,1号的左边是4,右边是8,上边是2,下边是16。所有的1号格子都是一样,这样保证了走步的一致性。
如果某格有子,其值等于0,如果没有子,其值就是表格的数值。
该表对马的走步和计算马的灵活度都很快捷。

16 4 1 8 2 16 4 1 8
8 2 16 4 1 8 2 16 4
4 1 8 2 16 4 1 8 2
2 16 4 1 8 2 16 4 1
1 8 2 16 4 1 8 2 16
16 4 1 8 2 16 4 1 8
8 2 16 4 1 8 2 16 4
4 1 8 2 16 4 1 8 2
2 16 4 1 8 2 16 4 1
1 8 2 16 4 1 8 2 16

首先定义一个表int table[90][32][8],并进行初始化。例如兰色的格子(其下标值=20)
table[20][1] = {9,18} , 意思是等于1时可以往左走
table[20][2]={13,22}
table[20][4]={1,3}
table[20][16]={37,29}
table[20][1|2]={9,18,13,22}, 意思是等于3时可以往左和往右走
下面的值就不一一列举了。

有了这样的数组就可以走子了。还是以蓝格子为例。
1、 计算occupy_board的值,如果有子=0,没有子=table,实际中occup_board可以随时更新.
2、 计算索引值index= occupy_board[20-1]| occupy_board[20+1]| occupy_board[20-9]| occupy_board][20+9]
3、 查表即可得到值。
wyx8421 2008-06-13
  • 打赏
  • 举报
回复
记得这个好像是叫"骑士巡游问题"吧?好像和"八皇后"是类似的问题

应该可以从"八皇后"得到灵感
junglesong 2008-06-12
  • 打赏
  • 举报
回复
这个题目有难度。
xibeitianlang 2008-06-12
  • 打赏
  • 举报
回复
注意,每走一步要更新M一次,即把初始位置能到达的格子的数字递减1。
xibeitianlang 2008-06-12
  • 打赏
  • 举报
回复
1、建一张9*10的表M,填上对应位置“马”能到达的格子数,比如角上为2,中间为8等等;
2、把初始位置标注为0,选该位置能到达的标注不为0的数字最小的格子作为新的初始位置;
3、重复步骤2,直至所有格子标注为0结束。
zgg___ 2007-07-24
  • 打赏
  • 举报
回复
在np问题的阴影下,对于马的历遍问题查了一些资料,这些资料貌似表明:对于n乘n的棋盘(n>4),当n为偶数时,有解;当n=5时,有解;当n为其他奇数时,还没有结论。因此,我想大家对7乘7或9乘9的棋盘的解的搜索或许是有意义的(当然也可以去证明无解咯)。
对于楼主提出的9乘10的情况,其解是容易搜索到的。下面是其中之一:1, 13, 5, 17, 9, 28, 7, 15, 3, 11, 23, 2, 14, 6, 18, 10, 29, 8, 20, 39, 27, 19, 38, 30, 49, 37, 16, 4, 12, 24, 32, 44, 25, 33, 21, 42, 34, 26, 45, 53, 41, 62, 81, 73, 61, 82, 63, 51, 72, 64, 56, 35, 47, 55, 36, 57, 65, 84, 76, 68, 87, 79, 60, 48, 40, 59, 80, 88, 67, 86, 74, 66, 85, 77, 89, 70, 78, 90, 69, 50, 58, 46, 54, 75, 83, 71, 52, 31, 43, 22。

felixskycao 2007-07-17
  • 打赏
  • 举报
回复
学习,等更详细的帖子或资料
clevercong 2007-07-16
  • 打赏
  • 举报
回复
J.C.Warnsdorff的规则来设计算法。在所有可走步的(尚未走过)方格中,马只能走向这样一个方格:从该方格出发,马可走的方格数为最少,如果可走步的方格数相等,则从马的当前位置来看,方向序号小的优先。
dogcai 2007-07-12
  • 打赏
  • 举报
回复
这个用递归很容易实现,不过一般不跑个2天是没有结果的,我试过了。
aa211314 2007-07-12
  • 打赏
  • 举报
回复
有意思
deng2000 2007-07-12
  • 打赏
  • 举报
回复
哈密尔顿遍历问题的算法复杂度是NP complete,也就是说非常可能是指数型增长的.象棋盘有64个点,可以想象其计算量是非常大的.
zgg___ 2007-06-29
  • 打赏
  • 举报
回复
To deng2000():

我弄错了,谢谢指点。
deng2000 2007-06-29
  • 打赏
  • 举报
回复
To zgg___():
此题是遍历图中所有节点,而不是遍历所有边.按图论术语,是哈密尔顿遍历问题而不是一笔画问题.
zgg___ 2007-06-29
  • 打赏
  • 举报
回复
关于一笔画的解决:
1、搜索所有节点,看看有奇数条通路的节点总数是不是超过2个,如果超过2个,game over。
2、从某奇数条通路节点或任意节点出发
3、随机前往下一节点,一直走到头,画出一条通路。
4、如果历遍了所就节点就结束,否则,断开某处的通路,将新的节点插入到通路中。
5、goto 3。


zgg___ 2007-06-29
  • 打赏
  • 举报
回复
如果告诉你一个图,一共有90个节点,并且告诉你90个节点之间如何相互连接的。那么你能够完成所谓的一笔画问题吗?
一个中国象棋棋盘恰好有90个节点,而马所走的日,规定了节点之间的连线。对于其它棋盘或情况也可以用类似的方法。

上面一贴的90打成72了,不好意思。
zgg___ 2007-06-29
  • 打赏
  • 举报
回复
如果告诉你一个图,一共有90个节点,并且告诉你72个节点之间如何相互连接的。那么你能够完成所谓的一笔画问题吗?
一个中国象棋棋盘恰好有90个节点,而马所走的日,规定了节点之间的连线。对于其它棋盘或情况也可以用类似的方法。
acmilan1984 2007-06-28
  • 打赏
  • 举报
回复
MARK,下班后练习一下。
加载更多回复(2)

33,008

社区成员

发帖
与我相关
我的任务
社区描述
数据结构与算法相关内容讨论专区
社区管理员
  • 数据结构与算法社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧