旅行商售货员问题的分支限界算法.doc
《旅行商售货员问题的分支限界算法.doc》由会员分享,可在线阅读,更多相关《旅行商售货员问题的分支限界算法.doc(6页珍藏版)》请在冰豆网上搜索。
旅行商售货员问题的分支限界算法
姓名:
学号:
一、实验目的与要求
1、掌握旅行商售货员问题的分支限界算法;
2、区分分支限界算法与回溯算法的区别,加深对分支限界法的理解。
二、实验题:
编程实现:
某售货员要到若干城市去推销商品,已知各城市之间的路程(或旅费)。
他要选定一条从驻地出发,经过每个城市一次,最后回到驻地的路线,使总的路程(或总旅费)最小。
三、实验提示
旅行商问题的解空间是一个排列树。
有两种实现的方法。
第一种是只使用一个优先队列,队列中的每个元素中都包含到达根的路径。
另一种是保留一个部分解空间树和一个优先队列,优先队列中的元素并不包含到达根的路径。
以下为第一种方法。
由于我们要寻找的是最小耗费的旅行路径,因此可以使用最小耗费分枝定界法。
在实现过程中,使用一个最小优先队列来记录活节点,队列中每个节点的类型为MinHeapNode。
每个节点包括如下区域:
x(从1到n的整数排列,其中x[0]=1),s(一个整数,使得从排列树的根节点到当前节点的路径定义了旅行路径的前缀x[0:
s],而剩余待访问的节点是x[s+1:
n-1]),cc(旅行路径前缀,即解空间树中从根节点到当前节点的耗费),lcost(该节点子树中任意叶节点中的最小耗费),rcost(从顶点x[s:
n-1]出发的所有边的最小耗费之和)。
当类型为MinHeapNode(T)的数据被转换成为类型T时,其结果即为lcost的值。
代码:
#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[