判断一个M*N的国际象棋马跳图是否有汉密顿回路

                 最近上了算法课,写了一个判断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;
	}
}


好的,根据你的要求,我对之前的代码进行了修改,现在能够读入多组数据,每组数据包括节点个数和节点序列。对于每个输入的序列,如果是汉密顿回路,就在一行中输出"YES",否则输出"NO"。代码如下: ``` #include <stdio.h> #include <string.h> #define MaxVex 210 int G[MaxVex][MaxVex]; // 邻接矩阵表示图 int visit[MaxVex] = {0}; int a[MaxVex] = {0}; int Nv, Ne; void Init() { // 读入图 scanf("%d%d", &Nv, &Ne); int i, j; for (i = 1; i <= Nv; i++) { for (j = 1; j <= Nv; j++) { G[i][j] = 0; } } for (i = 0; i < Ne; i++) { int v1, v2; scanf("%d%d", &v1, &v2); G[v1][v2] = G[v2][v1] = 1; // 无向图 } } // 判断序列是否是汉密尔顿回路 int isHamiltonian(int a[], int n) { int i, j; // 判断路径首尾是否相接 if (a[1] != a[n] || n != Nv) { return 0; } // 判断路径是否经过了所有顶点 memset(visit, 0, sizeof(visit)); visit[a[1]] = 1; for (i = 2; i <= Nv; i++) { j = a[i]; if (!G[a[i-1]][j] || visit[j]) { return 0; } visit[j] = 1; } return 1; } int main() { int k; scanf("%d", &k); while (k--) { Init(); int m; scanf("%d", &m); int i, j; for (i = 0; i < m; i++) { int n; scanf("%d", &n); for (j = 1; j <= n; j++) { scanf("%d", &a[j]); } if (isHamiltonian(a, n)) { printf("YES\n"); } else { printf("NO\n"); } } } return 0; } ``` 程序使用邻接矩阵表示图,使用isHamiltonian函数判断路径是否为汉密尔顿回路。在main函数中,首先读入数据组数k,然后循环读入每组数据,对于每个输入的序列,调用isHamiltonian函数判断是否为汉密尔顿回路
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值