货郎担问题(分支限界法)
#include<iostream>
#include<fstream>
using namespace std;typedef int Type;
#define N 5
#define ZERO_VALUE_OF_TYPE 0
#define MAX_VALUE_OF_TYPE 2147483647typedef 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值dd=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转换为原始行vk1node->row_cur[vk1] = -1; //原始行删除标志for(i=vk1+1;i<N;i++) //vk1之后的原始行,其对应的行号减一node->row_cur[i]--;vl1 = node->col_init[vl]; //当前列vl转换为原始列vl1node->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转换为当前行号kl=node->col_cur[vk]; //vk转换为当前列号lif((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); //选择分支方向并计算Dklznode=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):
运行结果:
货郎担问题(分支限界法)相关推荐
- 利用分支限界法解决01背包和货郎担问题
利用分支限界法解决01背包和货郎担问题详细步骤 原文链接:https://www.cnblogs.com/chihaoyuIsnotHere/p/10007086.html
- 算法设计与分析-TSP六种方法-贪心算法(最近邻点、最短链接)、蛮力法、动态规划法、回溯法、分支限界法、模拟退火
旅行商问题,即TSP问题(Travelling Salesman Problem)又译为旅行推销员问题.货郎担问题,是数学领域中著名问题之一.假设有一个旅行商人要拜访n个城市,他必须选择所要走的路径, ...
- 算法笔记之分支限界法
广度优先 广度优先搜索,其实就是层次遍历,程序采用队列来实现. 算法思想 从根开始,常以BF或以最小耗费(即最大收益)优先的方式搜索问题的解空间树.首先将根结点加入活结点表,接着从活结点表中取出根结点 ...
- 货郎担问题TSP(dp解法)
货郎担问题也叫旅行商问题,即TSP问题(Traveling Salesman Problem),是数学领域中著名问题之一. 题目背景 有n个城市,用1,2,-,n表示,城i,j之间的距离为dij,有一 ...
- 分支界限算法【0-1背包问题】按照优先队列式(LC)分支限界法求解0-1背包问题, 并给出限界函数,并画出该实例的状态空间树。
目 录 回溯算法[0-1背包问题] 分支界限算法[0-1背包问题] 作业题(期末考试必考) 小结 回溯算法[0-1背包问题] 分支界限算法[0-1背包问题] 解决思路:采用优先队列式分支限界 Ø ...
- 分支限界法实现最优装载c++_分支限界法
晓强Deep Learning的读书分享会,先从这里开始,从大学开始.大家好,我是晓强,计算机科学与技术专业研究生在读.我会不定时的更新我的文章,内容可能包括深度学习入门知识,具体包括CV,NLP方向 ...
- 回溯法(深度优先)剪枝和分支限界法(宽度优先)剪枝对比:01背包问题
限界函数: CurValue + rest <= BestValue 回溯法(深度优先)剪枝 # 递归方式 class pack_01_back_prune_test: def __init__ ...
- 分支限界法:单源最短路径--dijkstra算法
单源最短路径–dijkstra算法 前面已经多次介绍过dijkstra算法是贪心算法,是动态规划,实际上可以从分支限界的角度来理解: 分支限界法 分支限界法,实际上就是回溯法,一般意义的回溯法是基于深 ...
- 五大常用算法之五:分支限界法
http://www.cnblogs.com/steven_oyj/archive/2010/05/22/1741378.html 一.基本描述 类似于回溯法,也是一种在问题的解空间树T上搜索问题解的 ...
最新文章
- 独家 | creditR 的基于实践的导论:一个神奇的改良信用风险评分和验证的R包(附代码)...
- java transient关键字
- C++引用计数(reference counting)技术简介(2)
- C++11 非成员函数begin()、end()
- C#实现基于ffmpeg加虹软的人脸识别
- 7 位 CEO 创业自述:你熬过人生中最黑暗时刻的经历,是你成为强者的必然选择...
- 当我在做技术管理时,我在做什么?
- 快速排名系统询火星推荐_seo排名工具推荐10火星:比较好用的SEO长尾关键词
- 【Linux】——用户账号和组账号
- 眼睛怎么画?怎样才能画好人物的眼睛?
- oracle批量将id更新为uuid,oracle批量新增更新数据
- C++键盘记录器源码
- 【Java】Callable 接口
- 为什么不使用多线程?
- SQL下三种执行CMD命令的方法
- 2003服务器 临时文件,#Excel自动保存在哪#office 2003未保存的临时文件在哪个目录里?...
- 有限差分法-一维波动方程及其Matlab程序实现
- 回顾2016年存储市场发展 解析产品涨价为何如此逆天
- Oracle EBS财务模块(四)账套
- Redhat 7 下Mysql8.0.19安装配置图文详解(配合使用 centos YUM源)