穷举法、回溯法、分支界限法解决旅行商(TSP)问题

news/2024/10/31 3:16:54/

文章目录

  • 一、问题描述
  • 二、穷举法解决
    • 2.1 介绍
    • 2.2 代码
  • 三、回溯法解决
  • 四、分支界限法
    • 4.1 介绍
    • 4.2 代码


一、问题描述

 有一个旅行商由某城市出发,经过所有给定的 n n n 个城市后,再回到出发的城市。除了出发的城市外,其它城市只经过一回。这样的回路可能有多个,求其中路径成本最小的回路。

二、穷举法解决

2.1 介绍

 穷举法的本质是全排列。如下图对于四个点都连通的图,我们假定从 a a a 点出发,可以将获得 ( 4 − 1 ) ! (4-1)! (41)! 条路径。(公式为 ( n − 1 ) ! (n-1)! (n1)!

在这里插入图片描述

2.2 代码

#include <iostream>
using namespace std;//我们这里题目规模比较小 
int x[10]={0};         //城市编号数组,初值赋为0 
int bestx[10]={0};     //路线,初值赋为0 
int w = 0;             //过渡变量
int bestw = 1000;      //最优的费用void Tsp(int a[10][10], int n, int s)
{if (s == n){w = 0;//清零cout << "bestx: ";for (int i = 0; i < n; i++) {bestx[i] = x[i];cout << bestx[i] << " ";if (i < n - 1) {w += a[x[i]][x[i + 1]];}else {w += a[x[i]][x[0]];//回到起点的费用}}cout << "w:" << w << endl;if (bestw > w){bestw = w;//更新最优值}}else{for (int i = s; i < n; i++){//为什么要交换呢?因为要将x[s]作为起点进行往下搜索int t = x[i]; x[i] = x[s]; x[s] = t;Tsp(a, n, s + 1);t = x[i]; x[i] = x[s]; x[s] = t;}}
}int main()
{cout<<"请输入城市的个数: "<<endl; int n; //城市个数 cin>>n;for (int i = 0; i < n; i++){x[i] = i; //表示第i个城市编号,0到n-1}int a[10][10];  //a[i][j]表示从第i个城市到第j个的费用cout<<"请输入权值矩阵: "<<endl;for (int i = 0; i < n; i++) {for (int j = 0; j < n; j++) {cin >> a[i][j];}}Tsp(a, n, 1);//传1表示只搜从0开始的全排,传0表示所有全排cout << "最优的是:" << bestw << endl;return 0;
} 

在这里插入图片描述

三、回溯法解决

#include<iostream>
#include<algorithm>
#define MAX 10
using  namespace std;
int n;                   //城市个数
int a[MAX][MAX];         //城市间距离
int x[MAX];              //记录路径
int bestx[MAX]  = {0};   //记录最优路径
int bestp = 63355;       //最短路径长
int cp = 0;              //当前路径长
void backpack(int t){if(t>n){if((a[x[n]][1])&&(a[x[n]][1]+cp<bestp)){bestp = a[x[n]][1]+cp;for(int i = 1;i<=n;i++){bestx[i] = x[i];}}}else{for(int i = t;i<=n;i++){//约束为当前节点到下一节点的长度不为0,限界为走过的长度+当前要走的长度之和小于最优长度if((a[x[t-1]][x[i]])&&(cp+a[x[t-1]][x[i]]<bestp)){swap(x[t],x[i]);   cp+=a[x[t-1]][x[t]];backpack(t+1);cp-=a[x[t-1]][x[t]];swap(x[t],x[i]);}}}
}
int main(){cout<<"请输入城市的个数:"<<endl;cin>>n;      //顶点数for(int i = 1;i<=n;i++){x[i] = i;  //表示第i个城市编号 }cout<<"请输入权值矩阵:"<<endl;for(int i = 1;i<=n;i++){for(int j = 1;j<=n;j++){cin>>a[i][j];}}backpack(2);cout<<"最少旅行费用为:"<<bestp<<endl;cout<<"旅行路径为:"<<endl;for(int i = 1;i<=n;i++){cout<<bestx[i]<<" ";}cout<<bestx[1];return 0;
}

在这里插入图片描述

四、分支界限法

4.1 介绍

 分支限界法就是先将根结点放入活结点表中,然后循环取出表头结点,如果满足约束条件和限界条件就可以将当前结点的子结点(或者说下一级结点)放入活结点表中,直至得到所求解或者是活结点表为空为止。根据活结点表的存储方式可以将分支限界法分为队列式分支限界法和优先队列式分支限界法。这两种方法使用到的数据结构来是队列和堆,如有需要可以自己写,当然用直接用C++标准模板库中的queue和priority_queue会方便很多。

4.2 代码

#include <bits/stdc++.h>
#include <string>
#include <vector>
using namespace std;
#define MAXN 10int e[MAXN][MAXN];
int n, m, ans = 0x3f3f3f3f, vis[MAXN];
string anspath;void bfs(){queue<pair<string, int> > q;int dis = 0;vector<int> path;q.push({"1", 0});while(!q.empty()){string path = q.front().first;int dis = q.front().second;int pos = path[path.length()-1] - '0';if( path.length() == n ){dis += e[pos][1];if(dis < ans)   ans = dis, anspath = path + char(1 + '0');}else{for(int i = 1; i <= n; i ++ ){if(find(path.begin(), path.end(), (i + '0')) != path.end())    continue;if(dis + e[pos][i] > ans)   continue;q.push({path + char(i + '0'), dis + e[pos][i]});}}q.pop();}
}void show(){cout << ans << endl;for( int i = 0 ; i <= n ; i ++ )    cout << anspath[i] << (i == n ? "\n" : " ");
}int main(){cin >> n >> m;for( int i = 0 ; i < m ; i ++ ){int u, v, w;cin >> u >> v >> w;e[u][v] = e[v][u] = w;}bfs();cout << ans << endl;for( int i = 0 ; i <= n ; i ++ )    cout << anspath[i] << (i == n ? "\n" : " ");
}

http://www.ppmy.cn/news/1228959.html

相关文章

在bootstrap中,能不能对同一个容器,既使用类row进行网格设计,又使用类d-flex实现弹性盒子的性能?

问&#xff1a;在bootstrap中&#xff0c;能不能对同一个容器&#xff0c;既使用类row进行网格设计&#xff0c;又使用类d-flex实现弹性盒子的性能&#xff1f; 是的&#xff0c;你可以在Bootstrap中同时使用row类进行网格设计和d-flex类实现弹性盒子。这两个类可以结合使用&a…

asp.net校园二手交易平台系统VS开发sqlserver数据库web结构c#编程计算机网页

一、源码特点 asp.net校园二手交易平台系统 是一套完善的web设计管理系统&#xff0c;系统采用mvc模式&#xff08;BLLDALENTITY&#xff09;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为 vs2010&#xff0c;数据库为sqlserver2008&a…

Verilog基础:仿真时x信号的产生和x信号对于各运算符的特性

相关阅读 Verilog基础https://blog.csdn.net/weixin_45791458/category_12263729.html?spm1001.2014.3001.5482 信号爆x也许是所有IC人的噩梦&#xff0c;满屏的红色波形常让人头疼不已&#xff0c;但x信号的产生原因却常常只有几种&#xff0c;只要遵循一定的代码规范&#…

Docker基础知识总结

文章目录 1.Docker介绍2.Docker版本3.为什么要使用Docker4.Docker基础组件4.1 镜像&#xff08;Images&#xff09;4.2 容器&#xff08;Container&#xff09;和仓库&#xff08;Repository&#xff09; 5.Docker安装6.Docker run7.Dockerfile8.Docker commit9.镜像发布到镜像…

C++不同类型转换

内置类型的转换&#xff1a; 内置类型之间的转换之前提过。相同类型的赋值直接进行&#xff0c;但不同类型之间的赋值系统会将将其转换成临时变量&#xff0c;这个临时变量具有常性&#xff0c;然后再将这个临时变量进行赋值&#xff0c;这里就不做代码演示了。自定义类型转换为…

【C#】字符串拼接相关

目录 1.字符串拼接方式1 用号进行字符串拼接 复合运算符 2.字符串拼接方式2 3.控制台打印拼 4.例子 1.字符串拼接方式1 之前的算数运算符 只是用来数值类型变量进行数学运算的而 string 不存在算数运算符 不能计算 但是可以通过号来进行字符串拼接 用号进行字符串拼接 …

不想花大价钱?这10款替代Axure的平替软件更划算!

Axure是许多产品经理和设计师进入快速原型设计的首选工具&#xff0c;但Axure的使用成本相对较高&#xff0c;学习曲线陡峭&#xff0c;许多设计师正在寻找可以取代Axure的原型设计工具&#xff0c;虽然现在有很多可选的设计工具&#xff0c;但质量不均匀&#xff0c;可以取代A…

1.1二分查找

二分查找&#xff0c;主要是针对基本有序的数据来进行查找target。 二分法的思想很简单&#xff0c;因为整个数组是有序的&#xff0c;数组默认是递增的。 1.1 使用条件 用于查找的内容逻辑上来说是需要有序的查找的数量只能是一个&#xff0c;而不是多个 1.2 简介 首先选…