哈密尔顿回路问题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
哈密尔顿回路算法比较
一、贪心法贪心法通常用来解决具有最大值或最小值的优化问题。
通常从某一个初始状态出发,根据当前局部而非全局的最优决策,以满足约束方程为条件,以使得目标函数的值增加最快或最慢为准则,选择一个最快地达到要求的输入元素,以便尽快地构成问题的可行解。
贪心法通过一系列选择得到问题的解。
其所做出的每一个选择都是当前状态下的局部最好选择,即贪心选择。
贪心法并不总能得到问题的最优解。
利用贪心法解哈密尔顿回路的C++ 算法如下:
#include "stdio.h"
int G[8][8]={{0,2,8,1,9},
{2,0,5,10,9}, {8,5,0,5,3}, {1,10,5,0,5}, {9,9,3,5,0}};
struct Edge //记录边的信息
{
int x;
int y;
int value; //边的权值
};
typedef struct Edge Weight;
int T[5]={0}; // 用于标识节点是否被遍历过
int P[6]={0}; //存放路径
int sum_value=0; //计算总路径长度
Weight min_value(int r) // 找出当前节点具有最小权值的相邻边
{
int i,j=0,min;
Weight W[5]; //用于存放相邻边的信息for(i=0;i<5;i++)
{
if((T[i]==0)&&(i!=r)) //当节点未被遍历且不是自己到自己
{
W[j].x=r;
W[j].y=i;
W[j].value=G[r][i]; //记录相邻边的信息
j++;
}
}
min=W[0].value;
for(i=0;i<j-1;i++) // 从相邻边中找出具有最小权值的边
{ if(W[i+1].value<min)
{
W[0].x=W[i+1].x;
W[0].y=W[i+1].y;
W[0].value=W[i+1].value;
}
}
return W[0];
}
void ShortPath() // 寻找最短路径
{
int i,j,s=0;
P[s]=0; //起始点设为V0
Weight w_next; //存放路径上的下一结点for(i=1;i<5;i++) //有n 个节点循环n 次即可{
w_next=min_value(s); // 根据当前节点找出路径上的下一节点T[w_next.x]++;
//标识加入路径中的节点
T[w_next.y]++;
sum_value+=w_next.value;
P[i]=w_next.y; //记录加入路径的节点
s=w_next.y; //推移当前节点
}
P[i]=0; //回到起始点
sum_value+=G[s][0];
printf(" 无向图为:\n");
for(i=0;i<5;i++)
{
for(j=0;j<5;j++) printf("%d ",G[i][j]);
printf("\n");
}
printf("\n用贪心算法求得的哈密顿回路为:");
for(i=0;i<6;i++)
{
prin tf("V%d",P[i]);
if(i!=5)
prin tf("->");
}
printf("\n\n哈密顿回路的总路径长度为:%d\n",sum_value);
}
调试成功,如下图所示:
"D:2x 枝装文坤\ M £ Dev9 3\My P rojed d gfsd\D ebu g\sdf,eJ<e H
时间复杂度为0(n2)
二、贪心+分支限界
分支限界法常以广度优先或以最小耗费(最大效益)优先的方式搜索问题的解空间树。
在分支限界法中,每一个活结点只有一次机会成为扩展结点。
活结点一旦成为扩展结点,就一次性产生其所有儿子结点。
在这些儿子结点中,导致不可行解或导致非最优解的儿子结点被舍弃,其余儿子结点被加入活结点表中。
此后,从活结点表中取下一结点成为当前扩展结点,并重复上述结点扩展过程。
这个过程一直持续到找到所需的解或活结点表为空时为止。
#in clude"stdio.h"
#in clude"stdlib.h"
#define n 5 //结点个数为5
#define NoEdge 99999 /结点之间没有路径的标志
typedef int Type;
int G[n+1][n+1];// 图的权值矩阵
int S[n+1][n+1];// 每个顶点的连接边按序排列放入此矩阵
int VV[n+1];// 存放在哈密尔顿回路上的顶点
void sort_adj(int i)// 将各个顶点邻接的边按大小顺序存入{
int j,p,m,k;
Type temp;
for(j=1;j<=n;j++)
{
S[i][j]=j;
}
p=1;
l1:
for(j=p,k=j+1;G[i][S[i][j]]<=G[i][k];j=k,k++);
p=k;temp=G[i][k];m=k; while((temp<G[i][S[i][j]])&&(j>0))
{
S[i][j+1]=S[i][j];
j--;
}
S[i][j+1]=m;
if(p<n)
goto l1;
}
void sort_v() //对各顶点调用sort_adj()方法{
int i;
for(i=1;i<=n;i++)
sort_adj(i);
}
Type BTSP(int vv[]) {
Type c;
int U[n+1];
int V[n+1];
Type Cmin;
int i,j,l;
sort_v();
for(i=1;i<=n;i++)
U[i]=0;
U[1]=1;c=0;Cmin=NoEdge;l=1;V[1]=1; L0:
l++;j=0;
L1:
j++;
if(j>n)
goto L2;
if(U[S[V[l-1]][j]])
goto L1;
U[S[V[l-1]][j]]=1;
if(c+G[V[l-1]][S[V[l-1]][j]]>Cmin)
goto L1;
c+=G[V[l-1]][S[V[l-1]][j]];
V[l]=S[V[l-1]][j];
if(l<n)
goto L0;
if(c+G[S[V[l-1]][j]][1]<Cmin)
{
for(i=1;i<=n;i++)
VV[i]=V[i];
Cmin=c+G[S[V[l-1]][j]][1];
}
l++;
L2:
l--;
if(l>=2)
{
j=V[l];
U[j]=0;
c-=G[V[l-1]][j];
goto L1;
}
else if(Cmin!=NoEdge) return Cmin;
else return NoEdge;
}
void main()
{
int i;
G[1][1] = NoEdge;
G[1][2] = 1;
G[1][3] = 3;
G[1][4] = 4;
G[1][5] = 10;
G[2][1] = 1;
G[2][2] = NoEdge;
G[2][3] = 2;
G[2][4] = 2;
G[2][5] = 1;
G[3][1] = 3;
G[3][2] = 2;
G[3][3] = NoEdge;
G[3][4] = 4;
G[3][5] = 1;
G[4][1] = 4;
G[4][2] = 2;
G[4][3] = 4;
G[4][4] = NoEdge;
G[4][5] = 11;
G[5][1] = 10;
G[5][2] = 1;
G[5][3] = 1;
G[5][4] = 11;
G[5][5] = NoEdge;
if(BTSP(VV) != NoEdge) {
printf("最优值为:%d ", BTSP(VV)); printf("最优解为:");
for(i = 1; i <= n; i++) prin tf("%d-->",VV[i]);
prin tf("1\n");
}
else
{
printf("无回路");
prin tf("\n");
}
}
调试成功:
■ 'D: exe^ 装丈舛S Dev9 8\MyP roj ect^X^d gfsd\D e bu g\sdf. exe"
时间复杂度为0 (n2)。
三、回溯法
回溯法是一种按照深度优先的策略从根结点开始搜索解空间树的算法,该算法既带有系统性又带有跳跃性,它在包含问题的所有解的解空间树中,按照深度优先的策略,从根节点出发搜索解空间树。
算法搜索至解空间树的任一节点时,总是先判定该节点是否肯定不包含问题的解,如果肯定不包含,贝U跳过对以该节点为跟的子树的系统搜索,逐层向其祖先节点回溯。
否则,进入该子树,继续按深度优先的策略进行探索。
这种以深度优先的方式系统地搜索问题的解的算法称为回溯法。
回溯法可以用来求出问题的全
部解,也可以在求出问题的一个解之后停止对问题的求解,即只求该问题是否有解。
它适用于解一些组合数较大的问题。
利用回溯法解哈密尔顿回路存在性的C++算法如下:
#i nclude <iostream>
using namespace std;
bool road[8][8]={{0,1,0,0,1,0,0,0}
,{1,0,1,0,0,0,1,0}
,{0,1,0,1,0,1,0,0}
,{0,0,1,0,0,0,0,1}
,{1,0,0,0,0,1,0,0}
,{0,0,1,0,1,0,1,0}
,{0,1,0,0,0,1,0,1}
,{0,0,0,1,0,0,1,0}};
int x[8]={0};
void HaMiTonian(int );
void NextValue(int );
void display();
int main()
{
x[0]=1;
HaMiTonian(1);
return 0;
}
void HaMiTonian(int m)
{
if(m>7) return ;
L: NextValue(m);
if(x[m]==0)
return ; if(m==7&&road[0][x[7]-1]) display(); else
HaMiTonian(m+1);
goto L;
}
void NextValue(int k) {
int j;
l:x[k]=(x[k]+1)%9;
if(x[k]==0)
return ; if(road[x[k-1]-1][x[k]-1]) {
for( j=O;j<k;j++)
if(x[j]==x[k]) goto l; return ;
}
else goto l;
}
void display。
{
for(i nt i=0;i<8;i++)
cout<<x[i]vv" "; cout«e ndl;
}
调试成功,如下图:
J D:\exe 妄装交彳牛S D ev9 My P roj e ct d gfsd\De bug\5df.€xe rf
时间复杂度为0(n)
四、穷举法
#i nclude<stdio.h>
#i nclude<stdlib.h>
#i ncludevstri ng.h>
#define min(a,b) (a)<(b)?(a):(b)
#defi ne V 5
in t Len gth[V]={0};
int D[V][V]={
{0,6,4,5,8},
{6,0,3,2,7},
{4,3,0,3,1},
{5,2,3,0,2},
{8,7,1,2,0}
};
struct edge{
int fromV;
int toV;
int dist;
void set(int f,int t,int d){
fromV=f; toV=t; dist=d;
}
void operator=(const edge& e){ set(e.fromV,e.toV,e.dist);
}
};
static int comp(const void*e1,const void*e2){
if (((edge*)e1)->dist< ((edge*)e2)->dist)return -1;
else if(((edge*)e1)->dist==((edge*)e2)->dist)return 0;
else return 1;
}
const int len=16;
int Asum=0;
edge Path[V];
edge ArrE[len];
void printArrE(){
for(int p=0;p<len;++p){
printf("[%d,%d]=%d,",ArrE[p].fromV ,ArrE[p].toV ,ArrE[p].dist); } printf("\n"); }
void printPath(){
for(int p=0;p<V;++p){//printPath();
printf("[%d,%d]=%d,",Path[p].fromV ,Path[p].toV,Path[p].dist);
}
printf("\n");
}
void checkResult(){
printPath();
for(int i=0;i<V;++i){
for(int j=i+1;j<V;++j){ if(Path[i].fromV==Path[j].toV &&
Path[i].toV==Path[j].fromV)return;
}
}
int sum[V]={0}; for(int
s=0;s<V;++s){ sum[ Path[s].fr
omV ]++;
sum[ Path[s].toV ]++;
}
if(sum[0]==2 && sum[1]==2 && sum[2]==2 && sum[3]==2 &&
sum[4]==2){ printf("The best path is: ");
printPath(); exit(0);
}
}
#define x 1000
bool checkDuplicate(int c){ int F[V]={x,x,x,x,x}; int T[V]={x,x,x,x,x}; for(int
i=0;i<V-c;++i){ int j=0;
do{ if(Path[i].fromV==F[j] || Path[i].toV==T[j]){ return true;
} else{ F[j]=Path[i].fromV; T[j]=Path[i].toV; break;
} ++j;
}while(j<=i);
}
return false;
void replace(int c){//replace "count" elements at Path's tail printPath();
if(checkDuplicate(c))return;
for(int k=V-c;k<V;++k)Path[k]=ArrE[k];//restore tail information if(c==0){ checkResult();
return;
}
int start=V-c;
for(int i=start+1;i<len;++i){//i is the position in ArrE
Path[start]=ArrE[i];
replace(c-1);
}
}
int main(){
int tmp=V-1;
while(tmp){
}
Asum+=tmp;
--tmp;
}//For a solution, from/to vertex summary should be Asum printf("Asum=%d\n",Asum);
int idx=0;
for(int r=0;r<V;++r){
for(int c=0;c<V;++c){
if(r==c)continue;
ArrE[idx++].set(r,c,D[r][c]);
}
}
qsort(ArrE,len,sizeof(edge),comp);
printArrE();
for(int i=0;i<V;++i){
memcpy(Path,ArrE,sizeof(edge)*V);
replace(i);
}
printf("No circle found\n");
return 0;
}
调试成功,如下图:
"D:\ 亡羔輕喪文件\站S D ev98\MyProj ects\sdg fsd\Deb LI g\sdfe xe ”
时间复杂度为(n!)。