当s=n-1时,已找到的回路前缀是x[0:
n-1],它已包含图G的所有n个顶点。
因此,当s=n-1时,相应的扩展结点表示一个叶结点,此时该叶结点所相应的回路的费用等于cc和lcost的值,剩余的活结点的lcost值不小于已找到的回路的费用,它们都不可能导致费用更小的回路。
因此已找到叶结点所相应的回路是一个最小费用旅行售货员回路,算法结束时返回找到的最小费用,相应的最优解由数组v给出。
2.3算法实现
#include
#include
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;
pMiniHeap->pHead->pNext=NULL;
}
//入堆
voidput(MiniHeap*pMiniHeap,Nodenode){
Node*next;
Node*pre;
Node*pinnode=newNode;//将传进来的结点信息copy一份保存
//这样在函数外部对node的修改就不会影响到堆了
pinnode->cc=node.cc;
pinnode->lcost=node.lcost;
pinnode->pNext=node.pNext;
pinnode->rcost=node.rcost;
pinnode->s=node.s;
pinnode->pNext=NULL;
for(intk=0;kpinnode->x[k]=node.x[k];
}
pre=pMiniHeap->pHead;
next=pMiniHeap->pHead->pNext;
if(next==NULL){
pMiniHeap->pHead->pNext=pinnode;
}
else{
while(next!
=NULL){
if((next->lcost)>(pinnode->lcost)){//发现一个优先级大的,则置于其前面
pinnode->pNext=pre->pNext;
pre->pNext=pinnode;
break;//跳出
}
pre=next;
next=next->pNext;
}
pre->pNext=pinnode;//放在末尾
}
}
//出堆
Node*RemoveMiniHeap(MiniHeap*pMiniHeap){
Node*pnode=NULL;
if(pMiniHeap->pHead->pNext!
=NULL){
pnode=pMiniHeap->pHead->pNext;
pMiniHeap->pHead->pNext=pMiniHeap->pHead->pNext->pNext;
}
returnpnode;
}
//---------------------分支限界法找最优解--------------------------------
voidTraveler(){
inti,j;
inttemp_x[MAX_CITY_NUMBER];
Node*pNode=NULL;
intminiSum;//所有结点最小出边的费用和
intminiOut[MAX_CITY_NUMBER];
//保存每个结点的最小出边的索引
MiniHeap*heap=newMiniHeap;//分配堆
InitMiniHeap(heap);//初始化堆
miniSum=0;
for(i=0;iminiOut[i]=MAX_COST;//初始化时每一个结点都不可达
for(j=0;jif(City_Graph[i][j]>0&&City_Graph[i][j]//从i到j可达,且更小
miniOut[i]=City_Graph[i][j];
}
}
if(miniOut[i]==MAX_COST){//i城市没有出边
Best_Cost=-1;
return;
}
miniSum+=miniOut[i];
}
for(i=0;iBest_Cost_Path[i]=i;
}
Best_Cost=MAX_COST;//初始化的最优费用是一个很大的数
pNode=newNode;//初始化第一个结点并入堆
pNode->lcost=0;//当前结点的优先权为0也就是最优
pNode->cc=0;//当前费用为0(还没有开始旅行)
pNode->rcost=miniSum;//剩余所有结点的最小出边费用和就是初始化的miniSum
pNode->s=0;//层次为0
pNode->pNext=NULL;
for(intk=0;kpNode->x[k]=Best_Cost_Path[k];//第一个结点所保存的路径也就是初始化的路径
}
put(heap,*pNode);//入堆
while(pNode!
=NULL&&(pNode->s)//堆不空不是叶子
for(intk=0;kBest_Cost_Path[k]=pNode->x[k];//将最优路径置换为当前结点本身所保存的
}
/*
**pNode结点保存的路径中的含有这条路径上所有结点的索引
**x路径中保存的这一层结点的编号就是x[City_Size-2]
**下一层结点的编号就是x[City_Size-1]
*/
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>=0&&(pNode->cc+edge1+edge2)//edge1-1表示不可达
//叶子可达起点费用更低
Best_Cost=pNode->cc+edge1+edge2;
pNode->cc=Best_Cost;
pNode->lcost=Best_Cost;//优先权为Best_Cost
pNode->s++;//到达叶子层
}
}
else{//内部结点
for(i=pNode->s;iif(City_Graph[pNode->x[pNode->s]][pNode->x[i]]>=0){//可达
//pNode的层数就是它在最优路径中的位置
inttemp_cc=pNode->cc+City_Graph[pNode->x[pNode->s]][pNode->x[i]];
inttemp_rcost=pNode->rcost-miniOut[pNode->x[pNode->s]];
//下一个结点的剩余最小出边费用和
//等于当前结点的rcost减去当前这个结点的最小出边费用
if(temp_cc+temp_rcostfor(j=0;jtemp_x[j]=Best_Cost_Path[j];
}
temp_x[pNode->x[pNode->s+1]]=Best_Cost_Path[i];
//将当前结点的编号放入路径的深度为s+1的地方
temp_x[i]=Best_Cost_Path[pNode->s+1];//将原路//径中的深度为s+1的结点编号放入当前路径的
//相当于将原路径中的的深度为i的结点与深度W为s+1的结点交换
Node*pNextNode=newNode;
pNextNode->cc=temp_cc;
pNextNode->lcost=temp_cc+temp_rcost;
pNextNode->rcost=temp_rcost;
pNextNode->s=pNode->s+1;
pNextNode->pNext=NULL;
for(intk=0;kpNextNode->x[k]=temp_x[k];
}
put(heap,*pNextNode);
deletepNextNode;
}
}
}
}
pNode=RemoveMiniHeap(heap);
}
}
intmain()