旅行商问题之分支界限法(bfs)
Posted 11biscuits
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了旅行商问题之分支界限法(bfs)相关的知识,希望对你有一定的参考价值。
旅行商问题之分支界限法(bfs)
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
using namespace std;
const int INF=1e7;//正无穷
const int N=100;//最大地点容量
double graph[N][N];//地点邻接矩阵
int bestRoad[N];//最优路径
double bestlong;//最优路径长度
int n,m;
//排列树节点
struct Node{
double nowlong;//走过的长度
int index;//正在寻找第几个景点
int road[N];//路径
Node(){
}
Node(double _nowlong,int _index){
nowlong=_nowlong;
index=_index;//排列树层数
}
};
//定义优先队列优先级:nowlong越小越优先
bool operator < (const Node&a,const Node&b){
return a.nowlong>b.nowlong;
}
void init();//初始化
double bfs();//优先队列bfs
void print();//打印解
//主函数
int main(void){
int u,v,w;//u---v u,v为地点 w为二者之间的距离
cout<<"请输入景点的个数(即无向图节点个数)\\n";
cin>>n;
init();//初始化
cout<<"请输入景点之间的边数\\n";
cin>>m;
cout<<"请依次输入u v w,u:顶点 v:顶点 w:v--v距离\\n";
for(int i=1;i<=m;i++){
cin>>u>>v>>w;
graph[u][v]=graph[v][u]=w;
}
//广度优先求最优
bfs();
//输出最优解
print();
return 0;
}
//初始化
void init(){
//初始化最优路径长度:正无穷,因为要迭代求最优
bestlong=INF;
//初始化解向量
for(int i=0;i<=n;i++){
bestRoad[i]=0;
}
//初始化邻接矩阵
for(int i=0;i<=n;i++){
for(int j=i;j<=n;j++){
graph[i][j]=graph[j][i]=INF;//默认任意两点不可达
}
}
}
//打印解
void print(){
cout<<"最优路径:";
for(int i=1;i<=n;i++){
cout<<bestRoad[i]<<"--->";
}
cout<<1<<endl;
cout<<"最优路径长度:"<<bestlong<<endl;
}
//排列树
/*
* *(node 0)
* |1
* *(根节点)
* |2 |3 |4
* * * *
* |3 |4 |2 |4 |2 |3
* * * * * * *
* |4 |3 |4 |2 |3 |2
* * * * * * *
* */
//优先队列 bfs:默认从景点1出发
double bfs(){
//当前所在排列树的层数
int nowStep;
Node liveNode;//当前扩展节点
Node newNode;//生成新节点
//创建优先队列
priority_queue<Node> nodeQueue;
//创建根节点
newNode=Node(0,2);
for(int i=1;i<=n;i++){//初始化根节点的解向量
newNode.road[i]=i;
}
//根节点加入队列
nodeQueue.push(newNode);
while(!nodeQueue.empty()){
liveNode=nodeQueue.top();//最队头作为扩展节点
nodeQueue.pop();
nowStep=liveNode.index;//当前处理景区序号:开始时nowStep=2 因为第1层默认选景点1,直接跳过起点
if(nowStep==n){//到达了排列树倒数第二层时
//判断是不是解,是不是更优解
//判断当前节点到对应的叶子节点之间是否有路径 判断叶子节点到根节点是否有路径(因为要旅游一圈回到起点)
if(graph[liveNode.road[n-1]][liveNode.road[n]]!=INF&&graph[liveNode.road[n]][1]!=INF){
//判断是否是更优解
if(liveNode.nowlong+graph[liveNode.road[n-1]][liveNode.road[n]]+graph[liveNode.road[n]][1]<bestlong){
//迭代最优解长度
bestlong=liveNode.nowlong+graph[liveNode.road[n-1]][liveNode.road[n]]+graph[liveNode.road[n]][1];
//记录最优解的解向量
for(int i=1;i<=n;i++){
bestRoad[i]=liveNode.road[i];
}
}
continue;//结束队当前扩展节点的操作,是倒数第二层节点不用将叶子节点在入队列了,没必要
}
}
//判断是否满足扩展界限条件
//不扩展
if(liveNode.nowlong>=bestlong){//此方案,从起点到当前扩展节点的距离已经没有最优解优了
continue;
}
//扩展
//生成扩展节点的所有分支
for(int j=nowStep;j<=n;j++){
//如果扩展节点与分支节点之间有路径
if(graph[liveNode.road[nowStep-1]][liveNode.road[nowStep]]!=INF){
double templong=liveNode.nowlong+graph[liveNode.road[nowStep-1]][liveNode.road[j]];
if(templong<bestlong){//界限条件
newNode=Node(templong,nowStep+1);
for(int i=1;i<=n;i++){//复制以前的解向量
newNode.road[i]=liveNode.road[i];
}
swap(newNode.road[nowStep],newNode.road[j]);//交换road[nowStep]与road[j]
//新节点入队列
nodeQueue.push(newNode);
}
}
}
}
return bestlong;
}
测试样例
请输入景点的个数(即无向图节点个数)
4
请输入景点之间的边数
6
请依次输入u v w,u:顶点 v:顶点 w:v--v距离
1 2 15
1 3 30
1 4 5
2 3 6
2 4 12
3 4 3
最优路径:1--->4--->3--->2--->1
最优路径长度:29```
以上是关于旅行商问题之分支界限法(bfs)的主要内容,如果未能解决你的问题,请参考以下文章