用C语言解决棋盘上马遍历问题
程序员文章站
2022-05-22 12:37:27
...
题目三:棋盘上马遍历问题
(1)问题描述
在8*8方格的棋盘上,从任意指定的方格出发,为马寻找一条走遍棋盘每一个并且只能经过一次的一条路径。
(2)算法分析
如果用二维数组board[][]表示棋盘,其元素记录马经过该位置时的步骤号。另对马的各种可能的走法设定一个检索次序,确定了出发方格后首先要清盘,即将表示棋盘的二维数组每个元素都置0;第一步就是出发方格,主要是确定第二步到第六十四步。先找到马当前所在的各种可能的出口;该题中运用贪婪法多个出口中确定一个出口,选择下一个出口的贪婪标准是那些允许走的位置中选择下一个出口最少的那个位置,如马当前的位置在(i,j)只有三个出口,它们的位置是(i+2,j+1)、(i-2,j+1)和(i-1,j-2),如分别走到这三个位置,这三个位置又分别会有不同的出口,假定这三个位置的出口个数分别为4、2、3,则程序就选择让走向出口个数最少的(i-2,j+1)位置。该过程没有回溯,但对于某些开始位置实际上有解,而该算法不能找到解,对于这种情况,只要改变八种可能出口的选择顺序就能找到解。
数据分析
(3)源代码
#include<stdio.h>
#include<stdlib.h>
int chess[14][13]; //定义棋盘
int CanPath[14][13][8]; //每个棋子的八个方向哪些可以走
typedef struct{ //棋盘的八个方向
int x,y;
}direction;
direction dir[8]={{2,1},{1,2},{-1,2},{-2,1},{-2,-1},{-1,-2},{1,-2},{2,-1}}; //马遍历的八个方向
//栈的设计(顺序到达的各点坐标,还要有从前一点到达本点的方向)
typedef struct{
int x,y; //马的走过位置
int di; //马走的方向
}pathnode;
typedef struct{
pathnode pa[90];
int top;
}path; //顺序栈
void Init_Path(path *p)
{ //初始化栈
p->top=-1;
}
int Push_Path(path *p,pathnode t)
{ //进栈点及其向下一位移动的方向入栈
if(p->top>=89)
return -1;
else
{
p->top++;
p->pa[p->top].x=t.x;
p->pa[p->top].y=t.y;
p->pa[p->top].di=t.di;
return 1;
}
}
int Empty_path(path p)
{ //判断栈是否为空
if(p.top<0) return 1;
else return 0;
}
int Pop_Path(path *p,pathnode *t)
{ //出栈
if(Empty_path(*p))
return -1;
else
{
t->x=p->pa[p->top].x;
t->y=p->pa[p->top].y;
t->di=p->pa[p->top--].di;
return 1;
}
}
int Count(int x,int y)
{ //计算每个节点周围有几个方向可以走
int count=0,i=0;
for(i=0;i<8;i++)
if(chess[x+1+dir[i].x][y+1+dir[i].y]==0)
count++;
return count;
}
int Find_Direction(int x,int y)
{ //寻找下一个方向,如果找到返回值,否则为0
int dire,min=9,count,d=9;
for(dire=0;dire<8;dire++)
{
if(chess[x+1+dir[dire].x][y+1+dir[dire].y]==0 &&
CanPath[x+1][y+1][dire]==0)
{ count=Count(x+dir[dire].x,y+dir[dire].y);
if(min>count)
{min=count;
d=dire;
}
}
}if(d<9)
return d;
else
return -1;
}
void Mark_Dir()
{ //初始化,为栈的实现做准备,全部标记为0,表示八个方向都是通路
int i,j,k;
for(i=0;i<14;i++)
for(j=0;j<13;j++)
for(k=0;k<8;k++)
CanPath[i][j][k]=0; //马的遍历成功,即通路为0
}
void Mark_Che()
{ //标志棋盘函数,棋盘上区域内都为0,区域边缘设为1
int i,j;
for(i=0;i<14;i++) //首先全部标记为0
for(j=0;j<13;j++)
chess[i][j]=0;
for(i=0;i<2;i++) //前面两行标记为1
for(j=0;j<13;j++)
chess[i][j]=1;
for(j=0;j<2;j++) //前面两列标记为1
for(i=0;i<14;i++)
chess[i][j]=1;
for(j=11;j<13;j++) //后面两列标记为1
for(i=0;i<14;i++)
chess[i][j]=1;
for(i=12;i<14;i++)
for(j=0;j<13;j++) //后面两行标记为1
chess[i][j]=1;
}
void Horse(int x,int y) //x,y表示出发位置
{ //马的遍历函数
int num=1,t,i;
path p;
pathnode f;
Init_Path(&p);
for(num=1;num<=90;num++)
{
t=Find_Direction(x,y);
if(t!=-1)
{ //正常找到下一个方向的情况下
chess[x+1][y+1]=num;
f.x=x;
f.y=y;
f.di=t;
Push_Path(&p,f);
x=x+dir[t].x;
y=y+dir[t].y;
}
else if(num==90 && chess[x+1][y+1]==0)
{ //遍历到最后,t为-1
chess[x+1][y+1]=num;
f.x=x;
f.y=y;
f.di=t;
Push_Path(&p,f);
}
else
{
if(Pop_Path(&p,&f)==-1)
{ //出栈且栈为空的情况
printf("无法为您找到一条适合的路径!\n");
exit(0);
}
num-=2; //返回前一个点
x=f.x;
y=f.y;
CanPath[x+1][y+1][f.di]=1; //遍历不成功,即这个方向不通
}
}
//根据栈中信息打印出马的遍历路径
printf("马的遍历路径如下:\n ");
for(i=0;i<90;i++)
{
printf("(%2d,%2d)->",p.pa[i].x,p.pa[i].y);
if((i+1)%(8)==0)
printf("\b\b \n->");
}
}
void main()
{ //主函数
int x,y;
char ch='y';
printf(" 中国象棋马的遍历 \n");
printf("\n");
while(ch=='y')
{
Mark_Che();
Mark_Dir();
while(1)
{
printf("请输入入口点横坐标(在1-10之间):");
scanf("%d",&x);
if(x<1||x>10)
printf("输入错误,请重新输入!(横坐标在1-10之间)\n");
else
break;
}
while(1)
{
printf("请输入入口点纵坐标(在1-9之间):");
scanf("%d",&y);
if(y<1||y>9)
printf("输入错误,请重新输入!(纵坐标在1-9之间)\n");
else
break;
}
Horse(x,y);
getchar();
printf("\n");
printf("是否继续马的遍历(是:y;否:其他):");
fflush(stdin);
scanf("%c",&ch);
}
}
运行结果:
上一篇: Java多线程编程---线程锁与读写锁
下一篇: 【Matlab】简单甘特图绘制