图G的一个回路,若他通过每个节点一次,就是哈密顿回路
有一个判定条件是设图G具有n个定点的无向联通图,如果图G任意两个定点度数之和大于n,则G具有哈密顿回路,满足这个条件则一定是哈密顿图,但是哈密顿图不一定满足这个条件,最简单的例子就是一个n阶圈图
目前判断哈密顿回路没有高效的算法,因此大多数情况会要求你输出这个哈密顿回路,可以通过这个判定条件进行构造
1.任意找俩个相邻的节点S,T通过这两个节点向两头扩展直到不能扩展为止,因此所有与节点S,T相邻的节点全部在这条链上
2.若S与T相邻则形成了回路,若不相邻则需要构造出一个回路,设这条链上有k+2个节点,因为k≤N-2,又因为d(S)+d(T)≥N,因此必定存在vi和vj与S,T都相邻,并且满足j=i+1,因此可以把路径变为S->vi->T->vj则形成了一个回路
3.因为已经构造出了一个没有重复节点的回路,因此现在需要判断这条环路上的节点个数是否为N,如果等于N则以找出了哈密顿回路,否则因为图是联通的必然在环上有点与环外点相邻,所以从这断开继续进行第二步
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <iostream> #include <algorithm> using namespace std; int ans[505],vis[505],G[505][505]; int n,m; void revese(int *ans,int s,int t){ while(s<t){ swap(ans[s++],ans[t--]); } return; } void hamilton(){ int i,j,w,s=1,t,tmp,ansi; s=1,ansi=2; for(i=1;i<=n;i++) if(G[s][i]) break; t=i; vis[s]=vis[t]=1; ans[0]=s,ans[1]=t; while(1){ while(1){ for(i=1;i<=n;i++) if(G[t][i]&&!vis[i]){ ans[ansi++]=i; vis[i]=1; t=i; break; } if(i>n) break; } revese(ans,0,ansi-1); swap(s,t); while(1){ for(i=1;i<=n;i++) if(G[t][i]&&!vis[i]){ ans[ansi++]=i; vis[i]=1; t=i; break; } if(i>n) break; } //第一步将S与T尽可能扩展 if(!G[s][t]){ for(i=1;i<ansi-2;i++) if(G[ans[i]][t]&&G[s][ans[i+1]]) break; i++; t=ans[i]; revese(ans,i,ansi-1); } //判断是否形成了回路 if(ansi==n) return; for(j=1;j<=n;j++){ if(vis[j]) continue; for(i=1;i<ansi-2;i++) if(G[ans[i]][j]) goto next; } //没有的话则找哪个节点与外界相连 next: s=ans[i-1]; t=j; revese(ans,0,i-1); revese(ans,i,ansi-1); ans[ansi++]=j; vis[j]=1; } } int main(){ int i,j,a,b; while(scanf("%d%d",&n,&m)!=EOF&&(n||m)){ memset(vis,0,sizeof(vis)); memset(ans,0,sizeof(ans)); memset(G,0,sizeof(G)); for(i=1;i<=m;i++){ scanf("%d%d",&a,&b); G[a][b]=G[b][a]=1; //用邻接矩阵建图 } hamilton(); for(i=0;i<n;i++) printf("%d ",ans[i]); printf("\n"); } return 0; }