哈密顿图:图G的一个回路,若它通过图的每一个节点一次,且仅一次,就是哈密顿回路.存在哈密顿回路的图就是哈密顿图.哈密顿图就是从一点出发,经过所有的必须且只能一次,最终回到起点的路径.图中有的边可以不经过,但是不会有边被经过两次.
哈密顿回路之中的图并不要求是完全图,而当这个图的完全图也就是每个顶点之间都存在路径,并且是加权图的时候,哈密顿回路的问题就演变成了旅行商问题,因此上述两个问题的求解方法十分相似。
哈密顿回路:不重复地经过每个点,并最终能回到起始点的回路
有别于欧拉回路:不重复经过每条边的回路
哈密顿回路是点遍历
旅行商问题:求一条经过图中所有点且边权和最小的回路。
以下解法:
- 模拟退火
- 状压dp
- dfs
首先来求哈密顿回路问题
1.我们很容易想到用蛮力法,即对于给定的无向图(V,E) 依次考察图中所有顶点的全排列,而当满足相邻顶点之间存在边并且最后一个顶点与第一个顶点之间也存在边时就符合条件。
2.采用dfs,并且适当减枝。 下面我们采用这种方法求解
input:
5
0 1 1 1 0
1 0 1 0 1
0 1 0 1 1
1 0 1 0 1
0 1 1 1 0
//哈密顿回路问题
#include<stdio.h>
int x[100];
int visit[100];
int arc[6 ][6];
int n;
void dfs(int step)
{
int i,j;
if(step==n&&arc[x[step-1]][0]==1) //最后一步到达的顶点与起点之间存在路径
{
printf("路径:");
for(i=0;i<n;i++)
printf("%d ",x[i]+1);
printf("\n");
return ;
}
else
{
for(j=0;j<n;j++)
{
if(visit[j]==0&&arc[x[step-1]][j]==1) //j未访问并且当前顶点与j顶点之间存在路径
{
visit[j]=1;
x[step]=j; //下一个访问的顶点为j
dfs(step+1);
visit[j]=0;
x[step]=0;
}
}
}
}
int main(void)
{
int i,j;
scanf("%d",&n);
for(i=0;i<n;i++)
for(j=0;j<n;j++)
scanf("%d",&arc[i][j]);
visit[0]=1; //起点置为已经访问
x[0]=0;
dfs(1);
return 0;
}
旅行商问题的求解 :有若干个城市,任何两个城市之间的距离都是确定的,现要求一旅行商从某城市出发必须经过每一个城市且只在一个城市逗留一次,最后回到出发的城市,问如何事先确定一条最短的线路已保证其旅行的费用最少?
旅行商问题与哈密顿回路问题十分相似,都是经过每一个顶点一次最后回到出发的城市,不同的是旅行商问题对应的是完全图,即每个顶点之间都存在路径,并且路径长度已知。
input:
4
0 2 5 7
2 0 8 3
5 8 0 1
7 3 1 0
output:
11
//旅行商问题,对应完全图
//哈密顿回路问题 对应非完全图
#include<stdio.h>
int x[100];
int visit[100];
int arc[6][6];
int n,count,bestCount=9999999;
void dfs(int step,int count)
{
int i,j;
if(bestCount<count) //减枝,当然所经过的路径长度大于最小长度
return;
if(step==n) //已经走过n个顶点
{
count+=arc[x[step-1]][0];
bestCount=count;
return ;
}
else
{
for(j=0;j<n;j++)
{
if(visit[j]==0) //j未访问
{
visit[j]=1;//置为已经访问
x[step]=j; //访问该顶点
dfs(step+1,count+arc[x[step-1]][j]);
visit[j]=0;
x[step]=0;
}
}
}
}
int main(void)
{
int i,j;
scanf("%d",&n);
for(i=0;i<n;i++)
for(j=0;j<n;j++)
scanf("%d",&arc[i][j]);
visit[0]=1;
x[0]=0;
dfs(1,0);
printf("%d ",bestCount);
return 0;
}