哈密顿回路的算法
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了哈密顿回路的算法相关的知识,希望对你有一定的参考价值。
哈密顿路径问题在上世纪七十年代初,终于被证明是“NP完备”的。据说具有这样性质的问题,难于找到一个有效的算法。实际上对于某些顶点数不到100的网络,利用现有最好的算法和计算机也需要比较荒唐的时间(比如几百年)才能确定其是否存在一条这样的路径。
从图中的任意一点出发,路途中经过图中每一个结点当且仅当一次,则成为哈密顿回路。
要满足两个条件:
⒈封闭的环
⒉是一个连通图,且图中任意两点可达
经过图(有向图或无向图)中所有顶点一次且仅一次的通路称为哈密顿通路。
经过图中所有顶点一次且仅一次的回路称为哈密顿回路。
具有哈密顿回路的图称为哈密顿图,具有哈密顿通路但不具有哈密顿回路的图称为半哈密顿图。
平凡图是哈密顿图。
⒊若以1到2、2到3、3到4、4到5、5到1,为计数规律,则各点均出现两次;这种判断方法在计算机编程运算中显得尤为重要,其会精简很多运算过程。
⒋新出炉,有待检测的代码如下:
%-------输入的数据的原数据参照
% v1 v2 v3 v4 v5
%v1 0 20 1 11 2
%v2 0 0 9 1 3
%v3 0 0 0 13 8
%v4 0 0 0 0 6
%v5 0 0 0 0 0
%以上为输入数据的原数据参照
%建议所计算的数据矩阵长度为5,不会产生bug,且不会对任何计算机造成计算负担
%输入数据矩阵长度可以超过5,但是最初计算出的n个最小值中,重复次数超过2的点的种类只允许为一种
a=[0 20 1 11 2
0 0 9 1 3
0 0 0 13 8
0 0 0 0 6
0 0 0 0 0];
l=length(a)
s1=inf
zp=inf
n2=1
f=a
f(a==0)=inf
b=zeros(l)
i1=0
while i1<=l-1
[r c]=find(f==min(min(f)))
b(r⑴,c⑴)=f(r⑴,c⑴)
f(r⑴,c⑴)=inf
i1=i1+1
end
f1=f
[rz cz]=find(b>0)
pathz=[rz cz]
pz=[rz;cz]
p2z=zeros(2*l,1)
i2z=1
n2z=0
while i2z<=2*l
[r2z c2z]=find(pz==pz(i2z,1))
k1z=size(r2z)
if k1z(1,1)>2
p2z(r2z,1)=pz(r2z,1)
n2z=n2z+1
end
i2z=i2z+1
end
if n2z==2
HHL=b
zp=sum(sum(b))
else
while min(min(f1))~=inf
if n2>2
b=snh
end
[r1 c1]=find(b>0)
path1=[r1 c1]
p1=[r1;c1]
p2=zeros(2*l,1)
i2=1
n2=0
while i2<=2*l
[r2 c2]=find(p1==p1(i2,1))
k1=size(r2)
if k1(1,1)>2
p2(r2,1)=p1(r2,1)
n2=n2+1
end
i2=i2+1
end
[r3 c3]=find(p2>0)
p3=zeros(l,2)
i3=0
while i3<=n2-1
if r3⑴<=l
p3(r3⑴,:)=path1(r3⑴,:)
else
p3(r3⑴-l,:)=path1(r3⑴-l,:)
end
r3⑴=[]
i3=i3+1
end
p3(p3==0)=[]
p3=reshape(p3,n2,2)
p8=p2
[r8 c8]=find(p8>0)
p9=p8
r9=r8
i4=1
while i4<=n2
f1(p9(r9⑴,1),:)=inf
f1(:,p9(r9⑴,1))=inf
r9⑴=[]
i4=i4+1
end
[r4 c4]=find(f1==min(min(f1)))
f1(r4,c4)=inf
b1=b
b1(r4,c4)=a(r4,c4)
i5=1
p4=p3
while i5<=n2
b1=b
b1(r4⑴,c4⑴)=a(r4⑴,c4⑴)
b1(p4(1,1),p4(1,2))=0
p4(1,:)=[]
[r5 c5]=find(b1>0)
p5=[r5;c5]
i6=1
n6=0
while i6<=2*l
[r6 c6]=find(p5==p5(i6,1))
k6=size(r6)
if k6(1,1)>2
n6=n6+1
end
i6=i6+1
end
if n6>2
if sum(sum(b1))<s1
snh=[]
s1=sum(sum(b1))
snh=b1
end
else
if sum(sum(b1))<zp
HHL=[]
zp=sum(sum(b1))
HHL=b1
end
end
i5=i5+1
end
end
[rs cs]=find(HHL>0)
minpaths=[rs cs]
journeys=zp
注:这段代码采用分支定界法作为编写程序的依据,因此代码依旧局限在算法上;而且代码的使用对所要计算的数据是有要求的,如下:
⒈只要数据在开始计算出的n个最小值中,其重复次数超过2次的点的种类只能为一种,例如:代码段中的数据五个最小值中其重复次数超过2次的点只有v5。
⒉数据矩阵格式要求:只允许为上三角矩阵,不支持全矩阵以及下三角矩阵的运算。
⒊代码扩展方法请使用者独立思考,不唯一。
⒋运算数据扩展方法,请使用者独立思考,不唯一。
⒌此代码为本人毕设的附加产品,不会对使用此代码者,因理解不当或使用不当而造成的任何不良后果,付出任何责任。
⒍代码仅供交流。
哈密顿回路的算法是指:
在图论中是指含有哈密顿回路的图,闭合的哈密顿路径称作哈密顿回路。
哈密顿图(哈密尔顿图)(英语:Hamiltonian path,或Traceable path)是一个无向图,由天文学家哈密顿提出,由指定的起点前往指定的终点,途中经过所有其他节点且只经过一次。
这个问题和著名的七桥问题的不同之处在于,过桥只需要确定起点,而不用确定终点。哈密顿问题寻找一条从给定的起点到给定的终点沿 途恰好经过所有其他城市一次的路径。
参考技术B /*数据的存储结构为邻接多重表,解题的思路是深度优先递归再配合回溯算,特别注意的是对顶点和边的访问、禁用、还原、进栈、出栈等操作,因本人才C语言几个月代码不够规范,代码可行性还待检验,仅供学习交流使用,如有需改善或未考虑到的细节请各位大神指出!*/#include<stdio.h>
#include<windows.h>
#include<string.h>
#include<stdlib.h>
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define MAX_VER_NUM 11//顶点的最大数
#define MAX_ARC_NUM 22//边的最大数
typedef char VertexType;
typedef int Status;
typedef struct EdgeInfo
VertexType v1;
VertexType v2;
int weight;
EdgeInfo;
typedef struct ArcBox//边所包含的信息
int iver;
struct ArcBox *ilink;
int jver;
struct ArcBox *jlink;
int weight;//权值
int mark;
char *info;
ArcBox;
typedef struct VerBox//顶点所包含的信息
VertexType data;//顶点值
ArcBox *firstedge;//指向邻接点(边所包含的信息)
VerBox;
typedef struct Graph
int vernum;//顶点总个数
int arcnum;//边的总个数
VerBox vertexs[MAX_VER_NUM];//顶点信息
Graph;
typedef struct StackData//栈中可存放的数据
VertexType data;
int lenght;
struct StackData *pnext;
StackData;
typedef struct Stack//栈用于存放已访问过的顶点
struct StackData *ptop;
struct StackData *pbottom;
STNODE;
typedef struct Stack_Arc//存方已访问过的边及顶点
ArcBox *p[MAX_ARC_NUM];
int v_num[MAX_ARC_NUM];
SANode;
int Visited[MAX_VER_NUM];//标记顶点是否被访问过
EdgeInfo Data[MAX_ARC_NUM]='A','B',324,'A','J',419,'A','K',328,'A','D',241,'A','C',556,'A','F',703,'A','G',521,'B','G',391,
/**************************/'B','H',230,'B','I',356,'B','J',220,'C','F',642,'C','E',337,'D','F',829,'D','K',334,'E','F',581,
/**************************/'E','G',1254,'F','G',887,'G','H',242,'H','I',249,'I','J',713,'J','K',398;//边及权值
int Count=0;//记可走边的总数
STNODE Stack;//存放已访问过
SANode Store_Arc_Ver;//存放弧的信息及顶点信息
int LAV=-1,ALL=0;
int Short_Len=1000000,Short_Load=0;//存放最断最路经
void CreateGraph(Graph **G);//创建图
int LocateVer(Graph G,VertexType v);//查找顶点v在图中的位置
void ShowAdjInfo(Graph *G);//查看邻接点信息
int FirstAdjVer(Graph *G,int v,ArcBox **u);//第一邻接点
int NextAdjVer(Graph *G,int v,int w,ArcBox **u);//下一邻接点
void NAV(ArcBox *p,int *n,int v,int w,ArcBox **u);//递归查找下一邻接点
void InitArcBox_mark(ArcBox *p);//初始化mark的值
void DFSTraverse(Graph *G);//深度优先遍历图
void DFST(Graph *G,int v);//剃归深度优先遍历
void InitStack(void);//初始化栈
void Push(VertexType c);//数据进栈
void Pop(void);//出栈
void PrintfArc(ArcBox *p);//打印弧的信息
Status IsAdj(int *len,VertexType v);//判断栈顶的点是否与A为邻接点
int main()
Graph *G=NULL;
CreateGraph(&G);
printf("顶点的邻接表:\n");
ShowAdjInfo(G);printf("\n\n");
printf("可走路径结果:\n");
DFSTraverse(G);printf("\n");
printf("可走路径总数:%d条;最短路径为:路径%d,长度为:%d\n\n",ALL,Short_Load,Short_Len);
return 0;
void CreateGraph(Graph **G)//创建图
int i,j,k,w;
char v1,v2;
ArcBox *pnew;
(*G)=(Graph *)malloc(1*sizeof(Graph));
if((*G)==NULL)
printf("动态内存分配失败,程序终止!\n");
exit(-1);
(*G)->arcnum=MAX_ARC_NUM;
(*G)->vernum=MAX_VER_NUM;
for(i=0;i<(*G)->vernum;i++)
(*G)->vertexs[i].data='A'+i;
(*G)->vertexs[i].firstedge=NULL;
for(k=0;k<(*G)->arcnum;k++)
v1=Data[k].v1;
v2=Data[k].v2;
w=Data[k].weight;
i=LocateVer((**G),v1);
j=LocateVer((**G),v2);
if(i>=0&&j>=0)
pnew=(ArcBox *)malloc(1*sizeof(ArcBox));
if(pnew==NULL)
printf("动态内存分配失败,程序终止!\n");
exit(-1);
pnew->iver=i;
pnew->jver=j;
pnew->weight=w;
pnew->mark=FALSE;
pnew->ilink=(*G)->vertexs[i].firstedge;
pnew->jlink=(*G)->vertexs[j].firstedge;
(*G)->vertexs[i].firstedge=pnew;
(*G)->vertexs[j].firstedge=pnew;
else
printf("注意:*****顶点%c不存在!*****\n",i<0?v1:v2);
return;
int LocateVer(Graph G,VertexType v)//查找顶点v在图中的位置
int i,result=-1;
for(i=0;i<MAX_VER_NUM;i++)
if(G.vertexs[i].data==v)
result=i;
break;
return result;
void ShowAdjInfo(Graph *G)//查看邻接点信息
int v,w;
ArcBox *u;
for(v=0;v<G->vernum;v++)
printf("[%d|%c]",v,G->vertexs[v].data);
for(w=FirstAdjVer(G,v,&u);w>=0;w=NextAdjVer(G,v,w,&u))
printf("->[%d|%c|%d]",w,G->vertexs[w].data,u->weight);
InitArcBox_mark(G->vertexs[v].firstedge);
printf("\n");
int FirstAdjVer(Graph *G,int v,ArcBox **u)//第一邻接点
int w=-1;
ArcBox *p;
p=G->vertexs[v].firstedge;
(*u)=p;
if(v==p->iver)
w=p->jver;
p->mark=TRUE;
else if(v==p->jver)
w=p->iver;
p->mark=TRUE;
return w;
int NextAdjVer(Graph *G,int v,int w,ArcBox **u)//下一邻接点
int n=-1;
ArcBox *p;
(*u)=NULL;
p=G->vertexs[v].firstedge;
NAV(p,&n,v,w,&(*u));
return n;
void NAV(ArcBox *p,int *n,int v,int w,ArcBox **u)//递归查找下一邻接点
if(p->mark==FALSE && (p->iver==v ||p->jver==v))
(*u)=p;
if(p->iver==v)
*n=p->jver;p->mark=TRUE;
else if(p->jver==v)
*n=p->iver;p->mark=TRUE;
else printf("下一邻接点数据出错,请检查!\n");
else
if(p->ilink!=NULL && *n==-1)
NAV(p->ilink,n,v,w,&(*u));
if(p->jlink!=NULL && *n==-1)
NAV(p->jlink,n,v,w,&(*u));
return;
void InitArcBox_mark(ArcBox *p)//初始化mark的值
p->mark=FALSE;
if(p->ilink!=NULL)
InitArcBox_mark(p->ilink);
if(p->jlink!=NULL)
InitArcBox_mark(p->jlink);
return;
void DFSTraverse(Graph *G)//深度优先遍历图
int v;
for(v=0;v<G->vernum;v++)
Visited[v]=FALSE;
InitArcBox_mark(G->vertexs[v].firstedge);
InitStack();
DFST(G,0);
return;
void DFST(Graph *G,int v)//剃归深度优先遍历
int w=-1,flag=1,i=0,enter=1,len=0;
ArcBox *u;//邻接点
StackData *p;
Visited[v]=TRUE;
Count++;
Push(G->vertexs[v].data);
if(Count==11&&IsAdj(&len,Stack.ptop->data)==1)
ALL++;
printf("路径%-2d:",ALL);
printf("A");
p=Stack.ptop;
len=len+p->lenght;
if(Short_Len>len) Short_Load=ALL,Short_Len=len;
while(p!=Stack.pbottom)
printf("->%c",p->data);
p=p->pnext;
printf(" 总长度为:%d",len);
printf("\n");
for(w=FirstAdjVer(G,v,&u);w>=0;w=NextAdjVer(G,v,w,&u))
enter=1;
for(i=0;i<=LAV;i++)
if(Store_Arc_Ver.p[i]==u)
enter=0;
break;
if(enter==1)
Store_Arc_Ver.p[++LAV]=u;
Store_Arc_Ver.v_num[LAV]=v;
if(Visited[w]==FALSE)
DFST(G,w);
Visited[w]=FALSE;
Count--;
Pop();
for(LAV;Store_Arc_Ver.v_num[LAV]==v&&LAV>=0;)//还原当前顶点边的状态并出栈
Store_Arc_Ver.p[LAV]->mark=FALSE;
Store_Arc_Ver.p[LAV]=NULL;
LAV--;
void InitStack(void)//初始化栈
Stack.pbottom=Stack.ptop=(StackData *)malloc(1*sizeof(StackData));
Stack.pbottom->pnext=NULL;
return;
void Push(VertexType c)//数据进栈
StackData *pnew;
char v1,v2;
int i;
pnew=(StackData *)malloc(1*sizeof(StackData));
pnew->data=c;
if(c=='A')
pnew->lenght=0;
else
v1=c;
v2=Stack.ptop->data;
for(i=0;i<MAX_ARC_NUM;i++)
if((v1==Data[i].v1 || v1==Data[i].v2) && (v2==Data[i].v1 || v2==Data[i].v2))
pnew->lenght=Stack.ptop->lenght+Data[i].weight;
pnew->pnext=Stack.ptop;
Stack.ptop=pnew;
return;
void Pop(void)
StackData *p;
p=Stack.ptop;
Stack.ptop=p->pnext;
free(p);
void PrintfArc(ArcBox *p)
printf("[%d|%d|%d|%d] ",p->iver,p->jver,p->mark,p->weight);
if(p->ilink!=NULL)
PrintfArc(p->ilink);
if(p->jlink!=NULL)
PrintfArc(p->jlink);
Status IsAdj(int *len,VertexType v)//判断是栈顶的点是否与A为邻接点
int i;
for(i=0;i<MAX_ARC_NUM;i++)
if((Data[i].v1==v&&Data[i].v2=='A')||(Data[i].v1=='A'&&Data[i].v2==v))
*len=Data[i].weight;
return TRUE;
break;
return FALSE;
POJ 2438 哈密顿回路
Time Limit: 1000MS | Memory Limit: 65536K | |||
Total Submissions: 4730 | Accepted: 754 | Special Judge |
Description
Now we assume that there are 2 * n children who sit around a big table, and that none has more than n - 1 "enemies".
Input
There will be a blank line between input blocks. And m = n = 0 indicates the end of input and this case shouldn‘t be processed.
Output
Sample Input
1 0 2 2 1 2 3 4 3 6 1 2 1 3 2 4 3 5 4 6 5 6 4 12 1 2 1 3 1 4 2 5 2 6 3 7 3 8 4 8 4 7 5 6 5 7 6 8 0 0
Sample Output
1 2 4 2 3 1 1 6 3 2 5 4 1 6 7 2 3 4 5 8
解析 题目说保证 每个点的度数等于n所以 一定存在哈密顿回路 然后在他给出的图的补图上求一个哈密顿回路就可以了 套一个O(n*n)的板子。
哈密顿图:存在哈密顿回路的图
哈密顿图的判定:
一:Dirac定理(充分条件)
设一个无向图中有N个顶点,若所有顶点的度数大于等于N/2,则哈密顿回路一定存在.(N/2指的是?N/2?,向上取整)
二:基本的必要条件
设图G=<V, E>是哈密顿图,则对于v的任意一个非空子集S,若以|S|表示S中元素的数目,G-S表示G中删除了S中的点以及这些点所关联的边后得到的子图,则W(G-S)<=|S|成立.其中W(G-S)是G-S中联通分支数.
三:竞赛图(哈密顿通路)
N(N>=2)阶竞赛图一点存在哈密顿通路.
AC代码
1 #include <stdio.h> 2 #include <string.h> 3 using namespace std; 4 const int maxn = 500+10; 5 bool visit[maxn]; 6 int mapp[maxn][maxn],ans[maxn]; 7 int n,m; 8 inline void _reverse(int s, int t) //将数组anv从下标s到t的部分的顺序反向 9 { 10 int temp; 11 while(s < t) 12 { 13 temp = ans[s]; 14 ans[s] = ans[t]; 15 ans[t] = temp; 16 s++; 17 t--; 18 } 19 } 20 void Hamilton(int n) 21 { 22 memset(visit,false,sizeof(visit)); 23 int s = 1, t;//初始化取s为1号点 24 int ansi = 2; 25 int i, j; 26 int w; 27 int temp; 28 for(i = 1; i <= n; i++) if(mapp[s][i]) break; 29 t = i;//取任意邻接与s的点为t 30 visit[s] = visit[t] = true; 31 ans[0] = s; 32 ans[1] = t; 33 while(true) 34 { 35 while(true) //从t向外扩展 36 { 37 for(i = 1; i <= n; i++) 38 { 39 if(mapp[t][i] && !visit[i]) 40 { 41 ans[ansi++] = i; 42 visit[i] = true; 43 t = i; 44 break; 45 } 46 } 47 if(i > n) break; 48 } 49 w = ansi - 1;//将当前得到的序列倒置,s和t互换,从t继续扩展,相当于在原来的序列上从s向外扩展 50 i = 0; 51 _reverse(i, w); 52 temp = s; 53 s = t; 54 t = temp; 55 while(true) //从新的t继续向外扩展,相当于在原来的序列上从s向外扩展 56 { 57 for(i = 1; i <= n; i++) 58 { 59 if(mapp[t][i] && !visit[i]) 60 { 61 ans[ansi++] = i; 62 visit[i] = true; 63 t = i; 64 break; 65 } 66 } 67 if(i > n) break; 68 } 69 if(!mapp[s][t]) //如果s和t不相邻,进行调整 70 { 71 for(i = 1; i < ansi - 2; i++)//取序列中的一点i,使得ans[i]与t相连,并且ans[i+1]与s相连 72 if(mapp[ans[i]][t] && mapp[s][ans[i + 1]])break; 73 w = ansi - 1; 74 i++; 75 t = ans[i]; 76 _reverse(i, w);//将从ans[i +1]到t部分的ans[]倒置 77 }//此时s和t相连 78 if(ansi == n) return;//如果当前序列包含n个元素,算法结束 79 for(j = 1; j <= n; j++) //当前序列中元素的个数小于n,寻找点ans[i],使得ans[i]与ans[]外的一个点相连 80 { 81 if(visit[j]) continue; 82 for(i = 1; i < ansi - 2; i++)if(mapp[ans[i]][j])break; 83 if(mapp[ans[i]][j]) break; 84 } 85 s = ans[i - 1]; 86 t = j;//将新找到的点j赋给t 87 _reverse(0, i - 1);//将ans[]中s到ans[i-1]的部分倒置 88 _reverse(i, ansi - 1);//将ans[]中ans[i]到t的部分倒置 89 ans[ansi++] = j;//将点j加入到ans[]尾部 90 visit[j] = true; 91 } 92 } 93 int main() 94 { 95 while(scanf("%d%d",&n,&m)!=EOF) 96 { 97 if(n==0)break; 98 n*=2; 99 memset(mapp,0,sizeof(mapp)); 100 for(int i=1;i<=n;i++) 101 for(int j=1;j<=n;j++) 102 mapp[i][j]=i==j?0:1; 103 for(int i=0;i<m;i++) 104 { 105 int u,v; 106 scanf("%d%d",&u,&v); 107 mapp[u][v]=mapp[v][u]=0; 108 } 109 Hamilton(n); 110 printf("%d",ans[0]); 111 for(int i=1;i<=n-1;i++) 112 { 113 printf(" %d",ans[i]); 114 } 115 printf(" "); 116 } 117 }
该算法的详细过程及哈密顿回路的其他知识
https://www.cnblogs.com/Ash-ly/p/5452580.html
以上是关于哈密顿回路的算法的主要内容,如果未能解决你的问题,请参考以下文章