转载自:https://mp.weixin.qq.com/s/gLO9UffCMEqqMVxkOfohFA

Travelling Salesman Problem (TSP) 是最基本的路线问题。它寻求的是旅行者由起点出发,通过所有给定的需求点后,再次返回起点所花费的最小路径成本

动态规划算法(Dynamic Programming,简称DP)通常用于求解具有某种最优性质的问题,其基本思想是将待求解问题分解成若干个子问题,先求解子问题,然后由这些子问题的解再得到原问题的解。

假设现在有四个城市,它们分别是0,1,2,3,他们之间往来的代价如下图所示:

为了方便起见,把它化成二维表的形式:

这是一个最基本的TSP问题,且构成最优子结构性质,所以可以使用动态规划求解,下面来验证一下此方法求解的可行性。

设 s,s1,s2…s为满足题意的最短回路。假设从s到s1的路径已经确定,则问题转化为从s1到s的最短路径问题。而很显然,s1,s2…s一定可以构成一条最短路径,所以构成最优子结构性质,可以用动态规划求解。

明确问题可解,那下一步就是列方程求解了。

动态规划方程

V’ 表示一个点的集合,假设从顶点 s 出发,

d ( i , V’ )  表示当前到达顶点 i,经过 V’ 集合中所有顶点一次的最小花费

① 当 V’ 为仅包含起点的集合,也就是:

d ( s , { s } ) = 0 ;

② 其他情况,则对子问题求最优解。需在 V’ 这个城市集合中,尝试每一个城市结点,并求出最优解。

(要想计算全部点之间的最小路径,先单拿出一个点,然后对剩下点计算最小路径,依次向下迭代

③ 最后的求解方式为:

状态压缩

利用二进制以及位运算来实现对于本来应该很大的数组的操作。而求解动态规划问题,很重要的一环就是状态的表示,一般来说,一个数组即可保存状态

但是有这样的一些题目,它们具有DP问题的特性,但是状态中所包含的信息过多,如果要用数组来保存状态的话需要四维以上的数组。于是,我们就需要通过状态压缩来保存状态,而使用状态压缩来保存状态的DP就叫做状态压缩DP

例题TSP的动态规划方程中,V’ 是一个集合,而对于集合的状态表示最简单的办法就是利用C++STL里的set,但是这个时候就要考虑一个问题,在代码实现的时候,我们不能用一个集合去做一个数组的下标。自然而然,我们想到可以利用集合的特征值,但这个方法很复杂,而且不容易实现。

在这里普及一下位运算的知识。最简单的与(and),或 ( or ),非 ( not ), 大家都很熟悉,和逻辑电路是相通的。而对于异或 ( xor ), 则是很有趣的一种位运算,它的运算规则是相同为 0,不同为 1。例如:

1 xor 1 = 0,0 xor 0 = 0,

1 xor 0 = 1,0 xor 1 = 1;

它的运算满足交换律以及结合律。

再复杂一点的有左移 ( shl ), 右移 ( shr ),相当于对于二进制数的位置移动。例如10001(2) shl 1,就是10001(2)左移一位,变成了100010(2),换算成十进制,相当于扩大了 2 倍,同理右移则是缩减两倍。那么对于任意的一个二进制数,左移 k 位就是乘 2^k, 右移就是整除 2^k 。

|||| 小贴士:

在C++中,位运算操作符分别是:

&, |, ~,异或 ^

左移 <<,右移 >>

推到动态规划方程时,我们注意到 V’ 是一个数的集合,而且解决的问题规模比较小,于是可以用一个二进制数来存储这个集合。简单来说就是——如果城市 k 在集合 V’ 中,那么存储集合的变量 i第 k 位就为 1,否则为 0。由于有 n 个城市,所有的状态总数我们用 M 来表示,那么很明显:M = 2^n,而 0 到 2^n -1 的所有整数则构成了 V’ 的所有状态。这样,结合位运算,动归方程的状态表示就很容易了。

代码示例(C++)

#include<bits/stdc++.h>
using namespace std;
// 定义常量
const int INF = 0x3f3f3f3f;
#define sqr(x) ((x)*(x))
// 定义变量
string file_name;
int type; // type == 1 满秩矩阵格式, type == 2 二维坐标式
int s;
int N;// 城市结点数量
int init_point;
double **dp; // 动态规划状态数组dp[i][j],i表示集合V’,j表示当前到达的城市结点
double **dis; // 两个城市结点之间的距离
double ans;
// 定义结构体
struct vertex{double x, y; // 城市结点的坐标int id; // 城市结点的idint input(FILE *fp){return fscanf(fp, "%d %lf %lf", &id, &x, &y);}
}*node;double EUC_2D(const vertex &a, const vertex &b){return sqrt(sqr(a.x - b.x) + sqr(a.y - b.y));
}void io(){ // 数据读入printf("input file_name and data type\n");cin >> file_name >> type;FILE *fp = fopen(file_name.c_str(), "r");fscanf(fp, "%d", &N);node = new vertex[N + 5];dis = new double*[N + 5];if (type == 1){for (int i = 0; i < N; i ++){dis[i] = new double[N];for (int j = 0; j < N; j ++)fscanf(fp, "%lf", &dis[i][j]);}}else{for (int i = 0; i < N; i ++)node[i].input(fp);for (int i = 0; i < N; i ++){dis[i] = new double[N];for (int j = 0; j < N; j ++)dis[i][j] = EUC_2D(node[i], node[j]);// 计算城市之间的距离}}fclose(fp);return;
}void init(){ // 数据初始化dp = new double*[(1 << N) + 5];for(int i = 0; i < (1 << N); i++){dp[i] = new double[N + 5];for(int j = 0; j < N; j++)dp[i][j] = INF; } // 初始化,除了dp[1][0],其余值都为INFans = INF;return;
}double slove(){int M = (1 << N); // M就是第四部分所说的V’状态总数,1<<N表示2^N,总共有2^N种状态dp[1][0] = 0; // 假设固定出发点为0,从0出发回到0的花费为0。TSP只要求是一个环路,所以出发点可以任选for (int i = 1; i < M; i ++){ // 枚举V’的所有状态for (int j = 1; j < N; j ++){ // 选择下一个加入集合的城市if (i & (1 << j)) continue; // 城市已经存在于V’之中if (!(i & 1)) continue; // 出发城市固定为0号城市for (int k = 0; k < N; k ++){ // 在V’这个城市集合中尝试每一个结点,并求出最优解if (i & (1 << k)){ // 确保k已经在集合之中并且是上一步转移过来的结点dp[(1 << j) | i][j] = min(dp[(1 << j) | i][j], dp[i][k] + dis[k][j]); // 转移方程} // 将j点加入到i集合中}}}for (int i = 0; i < N; i ++)ans = min(dp[M - 1][i] + dis[i][0], ans);// 因为固定了出发点,所以要加上到城市0的距离。另外要从所有的完成整个环路的集合V’中选择,完成最后的转移return ans;
}int main(){io();init();string tmp = file_name + ".sol";FILE *fp = fopen(tmp.c_str(), "w");fprintf(fp, "%.2lf\n", slove());delete[] dp;delete[] node;delete[] dis;fclose(fp);return 0;
}

动态规划算法解Travelling Salesman Problem(TSP)问题相关推荐

  1. 旅行商问题(travelling salesman problem, TSP) 解题报告

    旅行商问题是个熟知的问题.这次是因为coursera上面选的算法课而写代码实现.这里做个简单总结. 测试程序: 25 20833.3333 17100.0000 20900.0000 17066.66 ...

  2. 旅行商问题(Travelling salesman problem, TSP)

    旅行商问题建模与证明 – 个人学习记录

  3. 单目标应用:求解单仓库多旅行商问题(Single-Depot Multiple Travelling Salesman Problem, SD-MTSP)的人工兔优化算法ARO

    一.算法简介 人工兔优化算法(Artificial Rabbits Optimization ,ARO)由Liying Wang等人于2022年提出,该算法模拟了兔子的生存策略,包括绕道觅食和随机躲藏 ...

  4. 动态规划算法解最长公共子序列LCS问题

    动态规划算法解LCS问题 作者 July 二零一零年十二月三十一日 本文参考:微软面试100题系列V0.1版第19.56题.算法导论.维基百科. 第一部分.什么是动态规划算法 ok,咱们先来了解下什么 ...

  5. PAT甲级1150 Travelling Salesman Problem:[C++题解]旅行商问题、图论

    文章目录 题目分析 题目链接 题目分析 来源:acwing 分析: 旅行商问题:访问每个城市并回到原城市的最短路. 思路: 1)判断相邻两点有无距离(NA):2)每个点是否都能到:3)是否是回路:4) ...

  6. cf1504. Travelling Salesman Problem

    cf1504. Travelling Salesman Problem 题意: n个城市,编号1~n,每个城市有美丽值a[i],现在要从城市1出发,其他所有城市走一遍,最后回到城市1,城市i到j的花费 ...

  7. PAT 1150 Travelling Salesman Problem(25 分)- 甲级

    The "travelling salesman problem" asks the following question: "Given a list of citie ...

  8. 旅行商问题(Traveling Salesman Problem,TSP)的+Leapms线性规划模型及c++调用

    知识点 旅行商问题的线性规划模型 旅行商问题的+Leapms模型及CPLEX求解 C++调用+Leapms 旅行商问题 旅行商问题是一个重要的NP-难问题.一个旅行商人目前在城市1,他必须对其余n-1 ...

  9. 【HDU 5402】Travelling Salesman Problem(构造)

    被某题卡SB了,结果这题也没读好...以为每一个格子能够有负数就当搜索做了.怎么想也搜只是去,后来发现每一个格子是非负数,那么肯定就是构造题. 题解例如以下: 首先假设nn为奇数或者mm为奇数,那么显 ...

  10. 1150 Travelling Salesman Problem (25 分)【难度: 难 / 知识点: 图 模拟 未完成】

    https://pintia.cn/problem-sets/994805342720868352/problems/1038430013544464384

最新文章

  1. Android源码项目目录结构
  2. Android之底部菜单TabHost的实现
  3. bzoj4429: [Nwerc2015] Elementary Math小学数学
  4. 基于fabric框架区块链实现科学数据出版系统
  5. ASP编程中的Microsoft JScript 编译错误 错误 '800a03ec'缺少;的解决方法.
  6. Duff in Love
  7. 数据结构(六)---队列的链式存储的实现---java版
  8. NoSQL架构实践(一)——以NoSQL为辅
  9. redis 8种淘汰策略
  10. XML转换JSON格式
  11. 2个网卡配置相同ip 华为交换机_华为交换机如何配置管理IP地址、如何修改管理IP地址...
  12. 如何判断本地(路由器)分配的IP是否是公网IP?
  13. Windows设置并切换代理服务器
  14. conver Json to map by fastJson
  15. 飞控中的IIR二阶滤波器
  16. 电源高性能和平衡区别 文件服务器,win10电源高性能和平衡区别具体有哪些细节...
  17. 与其被生活逼,不如被自己逼
  18. 使用js修改图片像素颜色并保存
  19. 特斯拉充电电流设置多大_特斯拉充电时间需要多久?汽车知识介绍
  20. 计算机中丢失swr.dll,win10系统提示模块initpki.dll加载失败如何解决

热门文章

  1. html实现雪花飘落
  2. Day15——Huffman编码之构建Huffman树
  3. windows11,Windows10,服务器centos7安装docker,docker compose
  4. U3D中ShaderForge插件使用系列教程之一
  5. ios13 微信提示音插件_ios13怎么设置微信提示音
  6. 网页直播源码IM即时通讯协议
  7. java直接控制飞鹅打印机_智慧餐厅,飞鹅智能云打印机设置教程
  8. android 侧滑栏教程,Android控件开发——DrawerLayout侧滑菜单的实现
  9. 简单的w7-->w10的方法
  10. 大学生面试 4个问题千万别撒谎