题目描述:
某旅行商希望从某城市出发经过一系列的城市最后再回到出发的城市。这些城市之间均可直航,他希望只经过这些城市一次且旅行的总线路最短。设有n个城市,城市的编号从1到n。
输入第一行为整数n,表示城市的数量。其后n行,每行有n个整数,用空格隔开,表示城市之间的距离。其中的第1个数表示城市1和城市2之间的距离,第2个数表示城市1和城市3之间的距离,…,第 n-1个数表示城市1和城市n之间的距离,依次类推。
解题思路:
给出一个样例,5个城市
二维表格表示城市之间的距离
0 | 4 | 8 | 6 | 5 |
4 | 0 | 3 | 2 | 10 |
8 | 3 | 0 | 8 | 7 |
6 | 2 | 8 | 0 | 3 |
5 | 10 | 7 | 3 | 0 |
显然我们可以想到有很多种路线,
1 ——> 2 ——> 3 ——> 4 ——> 5 ——> 1;
1 ——> 2 ——> 3 ——> 5 ——> 4 ——> 1;
如果把所有情况都列出来,显然是可以解决这个问题的(回溯法),利用动态规划去解决这个问题则需要去将这个问题分割成子问题,下面给出dp数组的含义以及分析过程:
dp[i][j] :从i 出发经过集合 j里面所有节点并回到起点的最小距离
乍一看可能觉得很蒙圈,下面给出几个dp[][]的值帮助理解
dp[1][0] = ? 1 代表第一个城市,也就是起点,0是点的集合,那么意思就是没有点,那么从1回到1的距离是0,dp[1][0] = 0;
dp[2][0] =? 2代表第二个城市,0的意思也是不需要再经过任何点,从2回到1的距离即dp[2][0]的值dp[2][0] = 4
以此类推,我们可以得到所有的dp[n][0],这也是dp的初始化的一部分,因为我们要计算的是经过所有城市的花费,那么dp[1][0]、dp[1][1]、dp[1][2]都是无意义的,我们只需要去计算dp[1][除了起点之外的所有城市]。
dp[2][1] = ?从2出发,经过1个城市回到1的值?
这里的1并不代表要经过多少个城市,因为这个问题本质上是组合问题,我们要去准确的知道经过的是哪些城市,而不是数量,因此 j 也就是这里的 1 是一个二进制数,利用二进制来表示要经过的点 1 == 0001 (5个城市除去起点还剩4个),注意这里并不表示第一个城市,回看我们的dp定义——从i 出发经过集合 j里面所有节点并回到起点,已经包含了回到起点,那么这里表示的其实是第二个城市。回到dp[2][1],从2出发经过 0001(就是第2个城市)那么显然这个是无意义的。它与dp[2][0]的意义相同。
到这应该能知道dp[3][1]代表的意思了,从3出发经过 0001(第2个城市)回到1的最小距离,那么怎么计算呢?
动态规划最重要的便是状态转移当前求的问题要能够从之前的问题求得。
3 ——> 2 ——> 1 可以看不可以看成
3 ——> 2 ——> 1 加粗的部分我们是不是已经计算过了?是的就是dp[2][0],
那么dp[3][1] = dp[2][0] + value[3][2](value[i][j]代表从i到j的距离)
dp[4][3] 的意思呢?
从4出发经过 0011(第2和3城市)回到1的最小距离,
有两种方案:4 ——> 3 ——> 2——> 1 4 ——> 2 ——> 3——> 1
第一种的状态转移:4 ——> 3 ——> 2——> 1 dp[4][3] = dp[3][1] + value[4][3];
第二种的状态转移:4 ——> 2 ——> 3——> 1 dp[4][3] = dp[2][2] + value[4][2];这里为什么是dp[2][2]呢?2 = 0010(也就是第三个城市)
显然将两者取min即使答案,至此基本的思路就解释完了,下面给出完整的dp表格以及代码,具体的细节就给读者自行体会了。文章来源:https://www.toymoban.com/news/detail-774375.html
文章来源地址https://www.toymoban.com/news/detail-774375.html
#include<iostream>
#include<vector>
#include<algorithm>
#include<time.h>
#include<sys/timeb.h>
using namespace std;
int main() {
int n;
cin >> n;
vector<vector<int>>value(n+1,vector<int>(n+1,0));
int dp_Size=(1 << (n - 1));
int ans = 10000;
vector<vector<int>>dp(n, vector<int>(dp_Size,10000));
vector<int>dp_ans(n - 1);
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
cin >> value[i][j];
}
}
for (int i = 1; i < n; i++) {
dp[i][0] = value[i + 1][1];
}
for (int i = 1; i < dp_Size-1; i++) {
for (int j = 1; j < n; j++) {
if ((1 << (j - 1) & i) != 0) {
continue;
}
for (int k = 1; k < n;k++) {
if (((1 << (k - 1)) & i)) { //按位与
dp[j][i] = min(dp[j][i], dp[k][i-(1<<(k-1))] + value[j+1][k + 1]);
dp_ans[j - 1] = dp[j][i];
}
}
}
}
for (int i = 1; i < n; i++) {
ans = min(ans, value[1][i + 1] + dp_ans[i - 1]);
}
/*for (int j = 0; j < n; j++) {
for (int i = 0; i < dp_Size; i++) {
cout << dp[j][i]<<" ";
}
cout << endl;
}*/
//打印dp数组
cout << endl;
/*for (int i = 0; i < n - 1; i++) {
cout << dp_ans[i]<<"\t";
}*/
cout << ans;
return 0;
}
到了这里,关于C++动态规划解决TSP(旅行商)问题的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!