#include<iostream>
#include<fstream>
using namespace std;
typedef int Type;
#define N 5
#define ZERO_VALUE_OF_TYPE 0
#define MAX_VALUE_OF_TYPE 2147483647
typedef struct node_data{
Type c[N][N]; //费用矩阵
int row_init[N]; //费用矩阵的当前行映射为原始行
int col_init[N]; //费用矩阵的当前列映射为原始列
int row_cur[N]; //费用矩阵的当前行映射为原始行
int col_cur[N]; //费用矩阵的当前列映射为原始列
int ad[N]; //回路顶点邻接表
int k; //当前费用矩阵的阶
Type w; //节点的下界
struct node_data *next; //队列链指针
}NODE;
Type c[N][N];
Type ad[N];
/*
NODE *xnode; //父亲结点指针
NODE *ynode; //儿子结点指针
NODE *znode; //儿子结点指针
NODE *qbase; //优先队列首指针
Type bound; //当前可行解的最优值
*/
//计算node所指向结点的费用矩阵行row最小值
Type row_min(NODE *node,int row,Type &second)
{
Type temp;
int i;
int flag=0;
if(node->c[row][0] < node->c[row][1]){
temp=node->c[row][0];
second=node->c[row][1];
}
else{
temp=node->c[row][1];
second=node->c[row][0];
}
for(i=2;i<node->k;i++){
if(node->c[row][i]<temp){
second=temp;
temp=node->c[row][i];
}
else if(node->c[row][i]<second)
second = node->c[row][i];
}
for(i=0;i<node->k;i++) //如果整行都是最大值则不进行归约,列同
if(node->c[row][i]==MAX_VALUE_OF_TYPE)
flag++;
if(node->k==flag)
return 0;
return temp;
}
//计算node所指向结点的费用矩阵列col最小值
Type col_min(NODE *node,int col,Type &second)
{
Type temp;
int i;
int flag=0;
if(node->c[0][col] < node->c[1][col]){
temp=node->c[0][col];
second=node->c[1][col];
}
else{
temp=node->c[1][col];
second=node->c[0][col];
}
for(i=2;i<node->k;i++){
if(node->c[i][col]<temp){
second = temp;
temp = node->c[i][col];;
}
else if(node->c[i][col]<second)
second=node->c[i][col];
}
for(i=0;i<node->k;i++)
if(node->c[i][col]==MAX_VALUE_OF_TYPE)
flag++;
if(node->k==flag)
return 0;
return temp;
}
//归约node所指向结点的费用矩阵
Type array_red(NODE *node)
{
int i,j;
Type temp,temp1,sum=ZERO_VALUE_OF_TYPE;
for(i=0;i<node->k;i++){ //行归约
temp=row_min(node,i,temp1); //行归约常数
for(j=0;j<node->k;j++){
if(node->c[i][j]==MAX_VALUE_OF_TYPE) //跳过最大值
continue;
node->c[i][j]-=temp;
}
sum += temp; //行归约常数累计
}
for(j=0;j<node->k;j++){ //列归约
temp=col_min(node,j,temp1); //列归约常数
for(i=0;i<node->k;i++){
if(node->c[i][j]==MAX_VALUE_OF_TYPE) //跳过最大值
continue;
node->c[i][j]-=temp;
}
sum+=temp; //列归约常数累计
}
return sum; //返回归约常数
}
//计算node所指向结点的费用矩阵Dkl,选择搜索分支的边
Type edge_sel(NODE *node,int &vk,int &vl)
{
int i,j;
Type temp,d=ZERO_VALUE_OF_TYPE;
Type *row_value = new Type[node->k];
Type *col_value = new Type[node->k];
for(i=0;i<node->k;i++) //每一行的次小值
row_min(node,i,row_value[i]);
for(i=0;i<node->k;i++) //每一列的次小值
col_min(node,i,col_value[i]);
for(i=0;i<node->k;i++){ //对费用矩阵所有为0的元素计算相应的temp值
for(j=0;j<node->k;j++){
if(node->c[i][j]==ZERO_VALUE_OF_TYPE){
temp=row_value[i]+col_value[j];
if(temp>d){ //求最大的temp值d
d=temp;
vk=i;
vl=j; //保存相应的行列号
}
}
}
}
delete row_value;
delete col_value;
return d;
}
//删除node所指向结点的费用矩阵第vk行第vl列的所有元素
void del_rowcol(NODE *node,int vk,int vl)
{
int i,j,vk1,vl1;
for(i=vk;i<node->k-1;i++) //元素上移
for(j=0;j<vl;j++)
node->c[i][j] = node->c[i+1][j];
for(j=vl;j<node->k-1;j++) //元素左移
for(i=0;i<vk;i++)
node->c[i][j] = node->c[i][j+1];
for(i=vk;i<node->k-1;i++) //元素上移及左移
for(j=vl;j<node->k-1;j++)
node->c[i][j] = node->c[i+1][j+1];
vk1 = node->row_init[vk]; //当前行vk转换为原始行vk1
node->row_cur[vk1] = -1; //原始行删除标志
for(i=vk1+1;i<N;i++) //vk1之后的原始行,其对应的行号减一
node->row_cur[i]--;
vl1 = node->col_init[vl]; //当前列vl转换为原始列vl1
node->col_cur[vl1]=-1; //原始列删除标志
for(i=vl1+1;i<N;i++) //vl1之后的原始列,其对应的列号减一
node->col_cur[i]--;
for(i=vk;i<node->k-1;i++){ //修改vk及其之后的当前行的对应原始行号
node->row_init[i] = node->row_init[i+1];
}
for(i=vl;i<node->k-1;i++) //修改vl及其之后的当前列的对应原始列号
node->col_init[i] = node->col_init[i+1];
node->k--; //当前矩阵的阶数减一
}
//登记回路顶点邻接表,旁路有关的边
void edg_byp(NODE *node,int vk,int vl)
{
int k,l;
vk=node->row_init[vk]; //当前行号转换为原始行号
vl=node->col_init[vl]; //当前列号转换为原始列号
node->ad[vk]=vl; //登记回路顶点邻接表
k=node->row_cur[vl]; //vl转换为当前行号k
l=node->col_cur[vk]; //vk转换为当前列号l
if((k>0)&&(l>=0)){ //当行、列号均处于当前矩阵中旁路相应的边
node->c[k][l] = MAX_VALUE_OF_TYPE;
}
}
//初始化
NODE *initial(Type c[][N],int n)
{
int i,j;
NODE *node=new NODE; //分配结点缓冲区
for(i=0;i<n;i++) //复制费用矩阵的初始数据
for(j=0;j<n;j++){
node->c[i][j]=c[i][j];
}
for(i=0;i<n;i++){ //建立费用矩阵原始行、列号与初始行、列号的关系
node->row_init[i]=i;
node->col_init[i]=i;
node->row_cur[i]=i;
node->col_cur[i]=i;
}
for(i=0;i<n;i++){ //回路顶点邻接表初始化为空
node->ad[i]=-1;
}
node->k=n;
return node; //返回结点指针
}
void Q_insert(NODE *qbase,NODE *xnode){
NODE *p;
if(qbase->next==NULL){
qbase->next=xnode;
xnode->next=NULL;
}
else if(xnode->w < qbase->next->w){
xnode->next=qbase->next;
qbase->next=xnode;
}
else{
p=qbase->next;
while(p->next){
if((xnode->w > p->w)&&(xnode->w < p->next->w)){
xnode->next=p->next;
p->next=xnode;
break;
}
p=p->next;
}
if(p->next==NULL){
p->next=xnode;
xnode->next=NULL;
}
}
p=qbase->next;
}
NODE *Q_delete(NODE *qbase){
NODE *p;
p=qbase->next;
qbase->next=p->next;
return p;
}
//货郎担问题的分支限界算法
template <class Type>
Type traveling_salesman(Type c[][N],int n,int ad[])
{
int i,j,vk,vl;
Type d,w,bound=MAX_VALUE_OF_TYPE;
NODE *xnode,*ynode,*znode,*qbase;
qbase=new NODE;
qbase->next=NULL;
xnode=initial(c,n); //初始化父亲结点
xnode->w = array_red(xnode); //归约费用矩阵
while(xnode->k!=0){
d=edge_sel(xnode,vk,vl); //选择分支方向并计算Dkl
znode=new NODE; //建立分支结点(右儿子结点)
*znode = *xnode; //x结点的数据复制到z结点
znode->c[vk][vl]=MAX_VALUE_OF_TYPE; //旁路Z结点的边
array_red(znode); //归约z结点的费用矩阵
znode->w = xnode->w + d; //计算z结点的下界
if(znode->w<bound) //若下界小于当前可行解最优值
Q_insert(qbase,znode); //z结点插入优先队列
else delete znode; //否则剪去该结点
ynode=new NODE; //建立分支结点(左儿子结点)
*ynode=*xnode; //x结点数据复制到y结点
edg_byp(ynode,vk,vl); //登记回路顶点的邻接表,旁路有关的边
ynode->c[vl][vk]=MAX_VALUE_OF_TYPE;
del_rowcol(ynode,vk,vl); //删除y结点费用矩阵当前vk行vl列
ynode->w = array_red(ynode); //归约y结点费用矩阵
ynode->w += xnode->w; //计算y结点的下界
if(ynode->k==2){ //费用矩阵只剩下2阶
if((ynode->c[0][0] == ZERO_VALUE_OF_TYPE)&&
(ynode->c[1][1] == ZERO_VALUE_OF_TYPE)){
ynode->ad[ynode->row_init[0]] = ynode->col_init[0];
ynode->ad[ynode->row_init[1]] = ynode->col_init[1];
}
else{
ynode->ad[ynode->row_init[0]] = ynode->col_init[1];
ynode->ad[ynode->row_init[1]] = ynode->col_init[0];
} //登记最后两条边
ynode->k=0;
}
if(ynode->w<bound){ //若下界小于当前可行解最优值
Q_insert(qbase,ynode); //y结点插入优先队列
if(ynode->k==0) //更新当前可行解最优值
bound = ynode->w;
}
else delete ynode; //否则剪去y结点
xnode=Q_delete(qbase); //取优先队列首元素
}
w=xnode->w; //保存最短路线费用
for(i=0;i<n;i++){ //保存路线的顶点邻接表
ad[i]=xnode->ad[i];
}
delete xnode; //释放x结点的缓冲区
while(qbase->next){ //释放队列结点缓冲区
xnode = Q_delete(qbase);
delete xnode;
}
return w; //回送最短路线费用
}
void main(){
int i,j;
ifstream fin("1.txt");
if(!fin){
cout<<"cannpt open file!"<<endl;
exit(0);
}
for(i=0;i<N;i++)
for(j=0;j<N;j++){
fin>>c[i][j];
}
fin.close();
cout<<"最小费用为:\n";
cout<<traveling_salesman(c,N,ad)<<endl;
cout<<"回路顶点邻接表登记情况为:"<<endl;
cout<<"\t";
for(i=0;i<N;i++)
cout<<i<<"\t";
cout<<endl;
cout<<"ad:\t";
for(i=0;i<N;i++)
cout<<ad[i]<<"\t";
cout<<endl;
}
fiel(1.text):
运行结果: