如果不是17楼顶了一下,我都不知道还有第三个程序并且还挖空了(估计除了九转没有谁会主动去填了)
~
这个程序其实就是和哈密顿回路有关,初初看可以填空并且能"正常运行",
然后久久稍微加改动了其它一点(可以说还是保持楼主原先的结果的),从哈密顿通路改成了哈密顿回路的判断~
程序代码:
#include <stdio.h>
#define FLAG 0
#define DEBUG
#define bd 8
void print(int a[][bd])
{//输出棋盘数据
int i,j;
for(i=0;i<bd;i++,printf("\n"))
for(j=0;j<bd;j++)printf("%-4d",a[i][j]);
}
int fun(int a[][bd],int x,int y,int s)
{//a:棋盘,x、y:坐标,s:步数
#define __SUCCESS 32767
int i,j,n,b[8][2]=
{
//改变移动顺序这个程序得出的结果是否有解会有所不同
{+2,+1},
{+1,+2},
{-1,+2},
{-2,+1},
{-2,-1},
{-1,-2},
{+1,-2},
{+2,-1},
}; //走马顺序
if(x<0||x>bd-1||y<0||y>bd-1)return 0;
#if FLAG
if (a[x][y]==1&&s==bd*bd+1)
return __SUCCESS;
#endif
if(a[x][y])return a[x][y]*10000; //返回该坐标周围符合马走日规则的数据,用于走途无路时剪枝参照
a[x][y]=s;
#if !FLAG
if (s==bd*bd)
return __SUCCESS;
#endif
for (i=j=0;i<8;i++)
{
n=fun(a,x+b[i][0],y+b[i][1],s+1);
if (n==__SUCCESS)
return __SUCCESS;
#undef __SUCCESS
if (n&&n<s)
{
a[x][y]=0;
return n; //剪枝
}
else if (n>10000&&n/10000<s-1&&n>j)
j=n; //确定剪枝数据
}
a[x][y]=0;
return j/10000;
//返回剪枝数据
}
void main()
{
//int a[bd][bd]={0};
//有些编译器不支持这样的初始化~
int a[bd][bd];
int i,j,k;
for (i=0;i!=bd;++i)
for (j=0;j!=bd;++j)
{
for (k=0;k!=bd*bd;++k)
(*a)[k]=0;
fun(a,i,j,1);
printf("i=%-4d,j=%-4d\n",i,j);
print(a);
#ifdef DEBUG
if (!**a)
getchar();
#endif
}
}
对以下代码说明和存在的问题作了一些补充~
1:当宏定义FLAG==0的时候是哈密顿通路,当FLAG==1的时候是哈密顿回路
2:这个在for循环输出了所有起始坐标的结果,但发现当bd=8的时候点(1,5)和点(6,5)是"无解"的~
具体细节可以通过是否定义宏DEBUG来判断是否在无解的情况下用getchar暂停~
3:当bd=8时至少存在一个点能输出哈密顿回路(当FLAG==1的时候),也就是说明正常来说所有点应该都有哈密顿回路,所以正常来说是所有点都是有解的而不是存在单独某个点无解是情况~
4:对棋盘跳马的顺序做了一些细节调整,主要是方便调试,交换了跳马顺序会影响到是否有解(正常来说跳马顺序和是否有解无关当然和解的顺序有关,但最终解集数不变)~
5:把重复标记映射从100改成了10000,这样支持了bd>=10的情况,但发现了当bd=12的时候,某些点输出比较快有些点比较慢(而是要等几秒甚至更久的那种)~
6:在调试的过程还曾经试过输出所有情况,发现bd=8的时候某个起点所有情况就那么几种,结合2,3的表现情况说明来看应该是漏解了,所以这个不是完全覆盖遍历,这个可能和程序本身的算法实现有关,具体个人感觉在
(n>10000&&n/10000<s-1&&n>j)
j=n; //确定剪枝数据
这里判断j的取值虽然剪枝了,但这样选8个方向走过的步数作为最多的作为回溯值这个怎么理解,8个方向怎么确定就是选那个方向是保证肯定有解的?~
7:当然如果是我填空本身就有问题而楼主那边没有那我就无话可说了~
当然所以楼主这个可以叫AI的启发式算法,具体怎么弄还是期待楼主说明吧
~
[此贴子已经被作者于2018-5-14 10:17编辑过]