旅行商问题Word格式文档下载.docx
《旅行商问题Word格式文档下载.docx》由会员分享,可在线阅读,更多相关《旅行商问题Word格式文档下载.docx(14页珍藏版)》请在冰豆网上搜索。
:
backtrack(inti)
{if(i==n){
if(a[x[n-1]][x[n]]!
=NoEdge&
&
a[x[n]][1]!
(cc+a[x[n-1]][x[n]]+a[x[n]][1]+a[x[n]][1]<
bestc||bestc==NoEdge)){
for(intj=1;
j<
=n;
j++)bestx[j]=x[j];
bestc==cc+a[x[n-1]][x[n]]+a[x[n]][1]};
}else{
For(intj=i;
=n;
j++)
//是否可进入x[j]子树?
If(a[x[i-1]][x[j]]!
=NoEdge&
(cc+a[x[i-1]][x[j]]<
bestc||bestc==NoEdge)){
//搜素子树
Swap(x[i],x[j]);
cc+=a[x[i-1]][x[i]];
Backtrack(i+1);
cc-=a[x[i-1]][x[i]];
}
}
Template<
TypeTSP(Type**a,intv[],intn,TypeNoEdge)
{Traveling<
Y;
//初始化Y
Y.x=newint[n+1];
//置x为单位排列
For(inti=1;
i<
i++)
Y.x[i]=i;
Y.a=a;
Y.n=n;
Y.bestc=NoEdge;
Y.bestx=v;
Y.cc=0;
Y.NoEdge=NoEdge;
//搜索x[2:
n]的全排列
Y.Backtrack
(2);
Delete[]Y.x;
ReturnY.bestc;
算法效率:
如果不考虑更新bestx所需的计算时间,则Backtrack需要O((n-1)!
)计算时间。
由于算法Backtrack在最坏情款下可能需要更新当前最优解O((n-1)!
)次,每次更新需O(n)计算时间,从而整个算法的计算时间复杂性为O(n!
)。
旅行商问题的分支界限法算法可描述如下:
使用优先队列来存储活节点,优先队列中的每个活节点都存储从根到该活节点的相应路径。
具体算法可描述如下:
ClassMinHeapNode{
firendTraveling<
;
Public:
OperatorType()const{returnlcost;
Private:
Typelcost,//子树费用的下界
cc,//当前费用
rcost;
//x[s:
n-1]中定点最小出边费用和
Ints,//根节点到当前节点的路径为x[0:
s]
//需要进一步搜索的顶点是x[s+1:
n-1]
};
四.算法实现
源程序代码
/*回溯法*/
#include<
stdio.h>
time.h>
#defineN5
doublecc,//当前路径费用
bestc;
//当前最优解费用
doublea[N+1][N+1];
//邻接矩阵,存放图的信息
intbestx[N+1];
//当前最优解
intx[N+1];
//当前解
voidinputAjac()
{
inti,j;
for(i=1;
i<
=N;
{for(j=i+1;
{
printf("
请输入第%d个城市到第%d个城市所需路费为:
"
i,j);
scanf("
%lf"
&
a[i][j]);
a[j][i]=a[i][j];
}
voidbacktrack(inti)
if(i==N)
{
if(a[x[N-1]][x[N]]>
0.0&
a[x[N]][x[1]]>
0.0)
if(bestc<
0.0||bestc>
cc+a[x[N-1]][x[N]]+a[x[N]][x[1]])
{
intj;
for(j=1;
{
bestx[j]=x[j];
bestc=cc+a[x[N-1]][x[N]]+a[x[N]][x[1]];
}
}
else
intj;
for(j=i;
if(a[x[i-1]][x[j]]>
if(bestc<
cc+a[x[i-1]][x[j]]+a[x[j]][x[1]])
inttemp;
cc+=a[x[i-1]][x[j]];
temp=x[i];
x[i]=x[j];
x[j]=temp;
backtrack(i+1);
cc-=a[x[i-1]][x[j]];
doubletsp()
inti;
{x[i]=i;
cc=0.0,bestc=-1.0;
inputAjac();
backtrack
(2);
returnbestc;
voidoutput()
printf("
%4d"
bestx[i]);
//printf("
\n"
);
voidmain()
doublestart,finish;
start=clock();
//取开始时间
printf("
城市个数:
5\n"
走%d个城市最少路费为:
%lf\n"
N,tsp());
路径:
output();
1\n"
finish=clock();
所需时间%fms\n"
(finish-start));
}
/*分支界限法*/
#include<
istream>
usingnamespacestd;
#defineMAX_CITY_NUMBER10
#defineMAX_COST10000000
intCity_Graph[MAX_CITY_NUMBER][MAX_CITY_NUMBER];
intCity_Size;
intBest_Cost;
intBest_Cost_Path[MAX_CITY_NUMBER];
typedefstructNode{
intlcost;
intcc;
intrcost;
ints;
intx[MAX_CITY_NUMBER];
structNode*pNext;
}Node;
typedefstructMiniHeap{
Node*pHead;
}MiniHeap;
voidInitMiniHeap(MiniHeap*pMiniHeap){
pMiniHeap->
pHead=newNode;
pHead->
pNext=NULL;
voidput(MiniHeap*pMiniHeap,Nodenode){
Node*next;
Node*pre;
Node*pinnode=newNode;
pinnode->
cc=node.cc;
lcost=node.lcost;
pNext=node.pNext;
rcost=node.rcost;
s=node.s;
for(intk=0;
k<
City_Size;
k++){
pinnode->
x[k]=node.x[k];
pre=pMiniHeap->
pHead;
next=pMiniHeap->
pNext;
if(next==NULL){
pMiniHeap->
pNext=pinnode;
}else{
while(next!
=NULL){
if((next->
lcost)>
(pinnode->
lcost)){
pinnode->
pNext=pre->
pre->
break;
pre=next;
next=next->
pre->
Node*RemoveMiniHeap(MiniHeap*pMiniHeap){
Node*pnode=NULL;
if(pMiniHeap->
pNext!
pnode=pMiniHeap->
pNext=pMiniHeap->
pNext->
returnpnode;
voidTraveler(){
inttemp_x[MAX_CITY_NUMBER];
Node*pNode=NULL;
intminiSum;
intminiOut[MAX_CITY_NUMBER];
MiniHeap*heap=newMiniHeap;
InitMiniHeap(heap);
miniSum=0;
for(i=0;
i<
i++){
miniOut[i]=MAX_COST;
for(j=0;
j<
j++){
if(City_Graph[i][j]>
0&
City_Graph[i][j]<
miniOut[i]){
miniOut[i]=City_Graph[i][j];
if(miniOut[i]==MAX_COST){
Best_Cost=-1;
return;
miniSum+=miniOut[i];
for(i=0;
i++){
Best_Cost_Path[i]=i;
Best_Cost=MAX_COST;
pNode=newNode;
pNode->
lcost=0;
cc=0;
rcost=miniSum;
s=0;
pNode->
x[k]=Best_Cost_Path[k];
put(heap,*pNode);
while(pNode!
=NULL&
(pNode->
s)<
City_Size-1){
for(intk=0;
Best_Cost_Path[k]=pNode->
x[k];
if((pNode->
s)==City_Size-2){
intedge1=City_Graph[(pNode->
x)[City_Size-2]][(pNode->
x)[City_Size-1]];
intedge2=City_Graph[(pNode->
x)[City_Size-1]][(pNode->
x)[0]];
if(edge1>
=0&
edge2>
cc+edge1+edge2)<
Best_Cost){
Best_Cost=pNode->
cc+edge1+edge2;
pNode->
cc=Best_Cost;
lcost=Best_Cost;
s++;
}else{
for(i=pNode->
s;
if(City_Graph[pNode->
x[pNode->
s]][pNode->
x[i]]>
=0){
inttemp_cc=pNode->
cc+City_Graph[pNode->
x[i]];
inttemp_rcost=pNode->
rcost-miniOut[pNode->
s]];
if(temp_cc+temp_rcost<
Best_Cost){
for(j=0;
j++){
temp_x[j]=Best_Cost_Path[j];
}
temp_x[pNode->
s+1]]=Best_Cost_Path[i];
temp_x[i]=Best_Cost_Path[pNode->
s+1];
Node*pNextNode=newNode;
pNextNode->
cc=temp_cc;
lcost=temp_cc+temp_rcost;
rcost=temp_rcost;
s=pNode->
s+1;
for(intk=0;
pNextNode->
x[k]=temp_x[k];
put(heap,*pNextNode);
deletepNextNode;
}
pNode=RemoveMiniHeap(heap);
intmain(){
scanf("
%d"
City_Size);
请分别输入每个城市与其它城市的路程花费:
City_Graph[i][j]);
Traveler();
最少路费:
%d\n"
Best_Cost);
所需时间:
%fms\n"
return1;
5.程序运行结果
回溯法结果截图:
分支界限法结果截图:
6.实验结果分析
回溯法算法的时间复杂度为O(n!
),分支界限发算法的时间复杂度为O(2^n);
从实验结果也可看出分支界限法所需时间少很多。
7.结论
分支限界法类似于回溯法,也是一种在问题的解空间树T上搜索问题解的算法。
但在一般情况下,分支限界法与回溯法的求解目标不同。
回溯法的求解目标是找出T中满足约束条件的所有解,而分支限界法的求解目标则是找出满足约束条件的一个解,或是在满足约束条件的解中找出使某一目标函数值达到极大或极小的解,即在某种意义下的最优解。
由于求解目标不同,导致分支限界法与回溯法在解空间树T上的搜索方式也不相同。
回溯法以深度优先的方式搜索解空间树T,而分支限界法则以广度优先或以最小耗费优先的方式搜索解空间树T。
分支限界法的搜索策略是:
在扩展结点处,先生成其所有的儿子结点(分支),然后再从当前的活结点表中选择下一个扩展对点。
为了有效地选择下一扩展结点,以加速搜索的进程,在每一活结点处,计算一个函数值(限界),并根据这些已计算出的函数值,从当前活结点表中选择一个最有利的结点作为扩展结点,使搜索朝着解空间树上有最优解的分支推进,以便尽快地找出一个最优解。
欢迎您的下载,
资料仅供参考!
致力为企业和个人提供合同协议,策划案计划书,学习资料等等
打造全网一站式需求