一、Tsp问题
假设有一个旅行商人要拜访n个城市,他必须选择所要走的路径,路径的限制是每个城市只能拜访一次,而且最后要回到原来出发的城市。路径的选择目标是要求得的路径路程为所有路径之中的最小值。
先生成相互距离二维表
二、动态规划
设s, s1, s2, …, sp, s是从s出发的一条路径长度最短的简单回路,假设从s到下一个城市s1已经求出,则问题转化为求从s1到s的最短路径,显然s1, s2, …, sp, s一定构成一条从s1到s的最短路径,所以TSP问题是构成最优子结构性质的,用动态规划来求解也是合理的。
三、编程思路
所谓状态压缩,就是利用二进制以及位运算来实现对于本来应该很大的数组的操作。而求解动态规划问题,很重要的一环就是状态的表示,一般来说,一个数组即可保存状态。但是有这样的一些题目,它们具有DP问题的特性,但是状态中所包含的信息过多,如果要用数组来保存状态的话需要四维以上的数组。于是,我们就需要通过状态压缩来保存状态,而使用状态压缩来保存状态的DP就叫做状态压缩DP。
代码中:
j=1时,i=1:3,d{1,{1}},d{2,{1}},d{3,{1}},第一个i和V有重复
j=2时,i=1:3,d{1,{2}},d{2,{2}},d{3,{2}},第二个i和V有重复
后面类似
d(i,V)第一个i只有一个数,而V中有很多数,保证i在V中不出现,即V 的二进制中第i-1为不是1即可。
四、代码
#include <iostream>
#include <stdio.h>
#include<iomanip>
using namespace std;
int dis[12][12], d[12][1 << 11];//距离地图表,d函数表,d[]为动态规划存储的城市经过矩阵
int main()
{
int n, temp,minDis;
给距离地图表赋值
cin >> n;
for (int i = 0; i < n; i++){
for (int j = 0; j < n; j++){
scanf_s("%d", &dis[i][j]);
}
}
//给d函数表赋值
for (int i = 1; i<n; i++){ //将所有城市到第0个城市的路径初始化为两市间的距离
d[i][0] = dis[i][0];
}
//除了第0行以外的其余
for (int j = 1; j<(1 <<(n-1)); j++){//j用二进制表示的城市集合,先说j再说i,动态规划从j的底层到上层,j数值越来越大
for (int i = 1; i<n; i++){
//i不在j表示的城市集合中,可以对d[i][j]赋值,否则赋0;
if (((1 << (i - 1))&j) == 0){
//temp=dis[i][k]+d[k][V-{k}]开始对V中所有的k进行遍历
int minDis = 60000;
for (int k = 1; k<n; k++){
if ((1 << (k - 1))&j) {//k表示的城市在j表示的城市集合中
temp = dis[i][k] + d[k][j - (1 << (k - 1))];
if (temp<minDis){//d(1,{2,3})=min{ C12+d(2,{3})||C13+d(3,{2})}
minDis = temp; //所有k中最小的距离
d[i][j] = minDis;//给d函数表每个位置赋值
}
}
}
}
}
}
//对第0行最后一个d(0,{123})赋值,d(0,{1,2,3})=min {C01+d(1,{2,3})|| C02+d{2,{1,3}}||C03+d{3,{1,2}})
minDis = 600;
for (int k = 1; k<n; k++){
temp = dis[0][k] + d[k][((1 << (n - 1)) - 1) - (1 << (k - 1))];//d[k][{123}-{k}]
if (minDis>temp){
minDis = temp;
d[0][(1 << (n - 1)) - 1] = minDis;
}
}
//此部分可以输出看看形成的d[][]矩阵,便于理解执行过程
for(int i=0;i<n;i++){
for(int j=0;j<(1<<(n-1));j++){
cout<<d[i][j]<<" ";
}
cout<<endl;
}
/*cout << d[0][(1 << n) - 1];*/
return 0;
}
特别感谢参考:https://blog.csdn.net/joekwok/article/details/4749713