关于马跳图的汉密顿回路问题


之前,自己写的那个回溯算法,效率非常低,因为他要遍历所有可能的路径,所以解决10以上的问题就会显得力不从心,甚至永远无法解出

下面是一个师姐写的算法,效率非常高,用到了贪心算法。避免了无止境的回溯,提高了效率。


#include  <iostream.h>  
#include  <iomanip.h>  
#include <time.h>
#define  ROW  6  
#define  LINE ROW       
#define  NUM  ROW*LINE         
int  board[ROW][LINE];
//两个数组存储对应的偏移量  
int  stepRow[8] ={-1,-2,-2,-1,1,2,2,1};  
int  stepLine[8]={-2,-1,1,2,2,1,-1,-2};  
//求  (i,j)  的出口数,各个出口对应的号存在 a[]  中。
int  exitn(int i,int j,int a[])
{  
	int  i1,j1,k,count;  
	for(count= k=0;k <8;k++){  
		i1=i+stepRow[k];  
		j1=j+stepLine[k];  
		if(i1>=0&&i1<ROW&&j1>=0&&j1<LINE&&board[i1][j1]==0){  
			a[count++]=k;  
		}  
	}  
	return  count;  
} 

 
//判断选择下个出口,s  是顺序选择法的开始序号  
int  next(int i ,int j){  
	int m,kk,a[8],b[8],temp;  
	m = exitn(i,j,a);  
	if(m==0)    
		return  -1;      //没有出口的情况 
	
	for(int min=9,k=0;k<m;k++){ //逐个考虑取下一步最少的出口的出口  
		temp=exitn(i+stepRow[a[k]],j+stepLine[a[k]],b);  
		if(temp<min){  
			min=temp;  
			kk =a[k];  
		}  
	}  
	return  kk;  
}  

int  main()  
{  
   int i,j,step,no,flag=0;  
        //对每个位置的点都进行计算得到各个点的结果 

   unsigned beg,end;
   beg=(unsigned)time(NULL);


   for(int sx=0;sx<ROW;sx++)  
	   for(int sy=0;sy<LINE;sy++)
	   {  
		  //start= 0;  
		  do{  
			  for(i=0;i<ROW;i++)  
				  for(j=0;j<LINE;j++)  
				      board[i][j]= 0;  
              board[sx][sy]= 1;  
              i=sx;j=sy;  
              for(step=2;step<=NUM;step++)
			  {  
				  if((no=next(i,j))== -1)  
                      break;  
                  i+=stepRow[no];  
                  j+=stepLine[no];  
                  board[i][j]=step;  
			  }  
			  if(step >NUM||no==-1)  
				  break;  
		  }while(step<=NUM); 
		  

		  int  stepRow[8] ={-1,-2,-2,-1,1,2,2,1};  
		  int  stepLine[8]={-2,-1,1,2,2,1,-1,-2};
		  //if(no!=-1&&((sx+2==i||sx-2==i)&&(sy+1==j||sy-1==j))||((sx+1==i||sx-1==i)&&(sy+2==j||sy-2==j)))
		  if(no!=-1&&( (sx-1==i&&sy-2==j)||(sx-2==i&&sy-1==j)||(sx-2==i&&sy+1==j)
			  ||(sx-1==i&&sy+2==j)||(sx+1==i&&sy+2==j)||(sx+2==i&&sy+1==j)||(sx+2==i&&sy-1==j)
			  ||(sx+1==i&&sy-2==j) ))

		  {  
			  cout<<"ok"<<endl;
			  for(i=0;i<ROW;i++)
			  {  
				  for(j=0;j<LINE;j++)  
					  cout<<setw(5)<<board[i][j];  //打印  
				  // cout<<board[i][j]<<'/t';
				  cout<<endl; 
				  
			  }
			  flag=1;
		  }
		  
		  if(flag)  break;
	   }
	   if(!flag)
	   {
		   cout<<"no circle"<<endl;
	   }

	   end=(unsigned)time(NULL);
	   cout<<endl<<"need"<<setw(3)<<end-beg<<" second"<<endl;
	   //cout<<endl<<"no circle"<<endl;
	   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、付费专栏及课程。

余额充值