最近上了算法课,写了一个判断M*N的马跳图中,是否存在汉密顿回路。用的是完全遍历的方法,这里没有使用递归的方法,一直遍历图中的路径节点,直到找到一条满足条件汉密顿回路则停止,当然,这样的算法效率比较低,特别是图中没有汉密顿回路时,要遍历所有可能的路径。
希望与大家共同学习,共同进步
后续会写一个用分支限界来判定的方法。。。敬请期待!
#include<stdio.h>
#define M 6 //行数
#define N 6 //列数
int islegal(int x, int y);
void main(void)
{
int flag[M][N]; //标注是否走过
int route[M*N][8]; //标注每个方向的路径是否可走,0为不可走,1为可走
//标记每一步的前一步的行和列
int fromcol[M*N]={0};
int fromrow[M*N]={0};
int direct[][2]={{-1,-2},{-2,-1},{-2,1},{-1,2},{1,2},{2,1},{2,-1},{1,-2}}; //每步可以走的八个方向
int curcol=-1; //当前行
int currow=-1; //当前列
int nextcol=-1; //下一行
int nextrow=-1; //下一列
// 初始化flag
int i,j;
for(i=0;i<M;i++)
{
for(j=0;j<N;j++)
{
flag[i][j]=0;
}
}
//初始化route
int k;
int pos; //当前在数组中的位置
for(curcol=0; curcol<M; curcol++)
{
for(currow=0; currow<N; currow++)
{
pos=curcol*N+currow;
for(k=0; k<8; k++)
{
nextcol=curcol+direct[k][0];
nextrow=currow+direct[k][1];
if(islegal(nextcol,nextrow))
{
route[pos][k]=1;
}
else
{
route[pos][k]=0;
}
}
}
}
//回溯遍历寻找路径
curcol=0;
currow=0;
pos=0;
int num=1;
while(num<=M*N) //当又回到原点时结束
{
for(i=0;i<8;i++) //寻找下一个合适的步
{
nextcol=curcol+direct[i][0];
nextrow=currow+direct[i][1];
if(nextcol==0 && nextrow==0 && num==M*N)
{
num++; //为了退出循环
break;
}
if(islegal(nextcol,nextrow) && flag[nextcol][nextrow]==0)
{
if(route[pos][i])
{
flag[curcol][currow]=1;
route[pos][i]=0; //防止回溯时走已走过的路
curcol=nextcol;
currow=nextrow;
pos=curcol*N+currow;
fromcol[pos]=curcol-direct[i][0]; //保存前一个点的位置
fromrow[pos]=currow-direct[i][1];
num++;
break;
}
}
}
if(i==8) //没有找到合适的步,进行回溯
{
if(flag[curcol][currow]==1)
{
flag[curcol][currow]=0;
}
pos=curcol*N+currow;
for(j=0; j<8; j++) //恢复退出的节点
{
if(islegal(curcol+direct[j][0],currow+direct[j][1]) && route[pos][j]==0)
{
route[pos][j]=1;
}
}
curcol=fromcol[pos];
currow=fromrow[pos];
pos=curcol*N+currow;
num--;
if(num==0)break;
}
}
printf("%d\n",num);
printf("%d,%d",curcol,currow);
if(num==0)
{
printf("无 汉密顿回路\n");
}
else if(num==M*N+1)
{
printf("有 汉密顿回路\n");
}
}
// 所在位置合法是返回值为1;否则返回0
int islegal(int x, int y)
{
if((x>=0 && x<M) && (y>=0 && y<N))return 1;
else
{
return 0;
}
}