此文章借鉴于博文https://blog.csdn.net/shujian_tianya/article/details/80873892,在此基础上重新进行了分析总结。

一、问题

二、想法





三、讲解

1、怎么求顶点子集,即这些怎么记录?
答:例如4个顶点{0,1,2,3},{1,2,3}依次为{},{1},{2},{1,2},{3},{1,3},{2,3},{1,2,3}。十进制数0、1、2、3、4、5、6、7的二进制分别为000、001、010、011、100、101、110、111。上述集合中的元素即为二进制中的位数,例如集合{2,3},可用二进制110(十进制6)代替,因为二进制110的第一位是0,第二位第三位是1。
整理一下思路——十进制数的二进制表示中,哪位为1则集合中就有哪个数。十进制6的二进制110中,第二三位是1,则6代表集合{2,3}
没有为什么,这是我们定下的一条规则,方便我们解题。
如此,过程矩阵d[i][j]的纵坐标j就多了一个含义。j=0,代表集合{ };j=1,代表集合{1}……j=5,代表集合{1,3}……以此类推。
大家可能发现一个问题,在4个顶点{0,1,2,3}中,十进制3代表{1,2},十进制4代表{3},而我们一般写的集合顺序是{},{1},{2},{3},{1,2},{1,3},{2,3},{1,2,3}。集合{3}是第3个,{1,2}是第4个。会发现顺序乱了,这个要说一下,集合之间的排序不影响此题的解答,读者朋友可以将集合以任意顺序写,会发现不影响最终结果的出现。

2、判断一个顶点是否位于子集中
举例解答,如要判断集合j={1,3,5,6,7}是否有顶点3。
集合j={1,3,5,6,7}表示成二进制串为1110101,其中集合里面有的数对应的位数写成1,没有的写成0。要在集合中找顶点3,就是要判断二进制串第3位是不是1,就把1110101右移(3-1)位,得到11101,然后结果和00001进行&运算,如果结果是1说明第3位是1,则说明顶点在子集中。
故判断公式为

(j>>(i-1))&1==1

3、填写过程矩阵过程
arc[i][j]为图的代价矩阵。
d[i][j]为过程矩阵,存放迭代结果。
以d[2][5]为例,d[2][5]=d(2,{1,3})。d[2][5] 表示从2出发,通过{1,3},最后回到起点。那么d[2][5] = min{arc[2][1] + d(1,{3}),arc[2][3] + d(3,{1})} = min{arc[2][1] + d[1][4],arc[2][3] + d[3][1]}。从2出发,要去{1,3},先考虑去1的路。去了1后集合{1,3}中只剩下{3} ,{3}对应二进制100,十进制4,所以要求的d表就是d[1][4],这个4可以通过(101)^(1)得到,而(1) = 1<<(1-1).其中,二进制101(十进制5)代表集合{1,3};再看去3的路,去了3后集合{1,3}中只剩下{1},{1}对应二进制001,十进制1,所以要求的d表就是d[3][1],1通过(101) ^ (100)得到,而(100) = 1<<(3-1)。故此处又总结出一个公式

d[i][j] = min{arc[i][k] + d[k][j ^ (1 << (k - 1))]}

四、代码

#include<iostream>
#include<iomanip>
using namespace std;
struct rode {int x;int y;int z;
}rode[100][100];//记录过程矩阵中的路线,由点x出发,先经过点k,再经过集合z,过程矩阵j[i][j]中的j就代表集合
int main()
{int n, i, j, k, m = 1;cout << "顶点个数:";cin >> n;for (i = 1; i < n; i++)//n个顶点有m个子集,m=2^(n-1)m = m * 2;//创建动态数组,节省空间int **arc = new int*[n];//图的代价矩阵for (i = 0; i < n; i++)arc[i] = new int[n];int **d = new int*[n];//存放迭代结果,即过程矩阵,过程表for (i = 0; i < n; i++)d[i] = new int[m];//输入图的代价矩阵cout << "请以矩阵形式输入顶点之间的距离" << endl;for (i = 0; i < n; i++)for (j = 0; j < n; j++)cin >> arc[i][j];//纠正用户输入的数据for (i = 0; i < n; i++)arc[i][i] = -1;cout << "您输入的顶点之间的距离如下" << endl;for (i = 0; i < n; i++){for (j = 0; j < n; j++)cout << setw(3) << arc[i][j];cout << endl;}//初始化第0列for (i = 0; i < n; i++)d[i][0] = arc[i][0];//填过程矩阵,第一行,因为第一行代表从顶点0开始经过一些顶点再回到0,但是我们只需要d[0][m-1]这一个值,所以第一行先不计算,等最后再只计算d[0][m-1],节省时间。for (j = 1; j < m; j++)//j就代表m个子集,如j=5(二进制为101)代表{1,3},j=3(二进制为011)代表{1,2}。二进制1011就代表集合{1,2,4}。这是设定的一种规则。{for (i = 1; i < n; i++){d[i][j] = 0x7ffff;//设0x7ffff为无穷大if (((j >> (i - 1)) & 1) == 1)    //对于数字x,要看它的第i位是不是1,通过判断布尔表达式 (((x >> (i - 1) ) & 1) == 1的真值来实现continue;                  //若第i位是1,就说明子集j里包含i这个元素,d[i][j]这个空就无需计算for (k = 1; k < n; k++){/*找出集合j中有哪些元素,比如,(6>>(2-1))&1==1,说明集合{2.3}中有元素2。之所以这么做,是因为我们人知道j=6(二进制110)代表集合{2.3},但是计算机不知道,所以要有找元素这一步*/if (((j >> (k - 1)) & 1) == 0)    //集合中没有此元素就跳过continue;/*以d[2][5]为例,d[2][5]=d(2,{1,3})。d[2][5] 表示从2出发,通过{1,3},最后回到起点。那么d[2][5] = min{arc[2][1] + d(1,{3}),arc[2][3] + d(3,{1})} = min{arc[2][1]  + d[1][4],arc[2][3] + d[3][1]}。从2出发,要去{1,3},先考虑去1的路。去了1后集合{1,3}中只剩下{3} ,{3}对应二进制100,十进制4,所以要求的d表就是d[1][4],这个4可以通过(101)^(1)得到,而(1) = 1<<(1-1).其中,二进制101(十进制5)代表集合{1,3};再看去3的路,去了3后集合{1,3}中只剩下{1},{1}对应二进制001,十进制1,所以要求的d表就是d[3][1],1通过(101) ^ (100)得到,而(100) = 1<<(3-1)。*/if (d[i][j] > arc[i][k] + d[k][j ^ (1 << (k - 1))]){d[i][j] = arc[i][k] + d[k][j ^ (1 << (k - 1))];rode[i][j].x = i;rode[i][j].y = k;rode[i][j].z = j ^ (1 << (k - 1));//由x出发,先经过k,再经过集合z}}}}//计算d[0][m-1],d(0,{1,2,3})=min{arc[0][1]+d(1,{2,3}),arc[0][2]+d(2,{1,3}),arc[2][3]+d(3,{1,2})}for (j = 0; j < m - 1; j++)d[0][j] = -1;d[0][m - 1] = 0x7ffff;for (k = 1; k < n; k++){if ((( m-1 >> (k - 1)) & 1 ) == 0) continue;if (d[0][m - 1] > arc[0][k] + d[k][(m - 1) ^ (1 << (k - 1))]){d[0][m - 1] = arc[0][k] + d[k][(m - 1) ^ (1 << (k - 1))];rode[0][m - 1].x = 0;rode[0][m - 1].y = k;rode[0][m - 1].z = (m - 1) ^ (1 << (k - 1));}}cout << "最短路径为:" << d[0][m-1] << endl;//输出路线j = m - 1;cout << "0→";for (i=0;i<n-1;i++){cout << rode[i][j].y << "→";j = rode[i][j].z;}cout<< rode[i][j].y << endl;//输出过程矩阵cout << "过程矩阵为:" << endl;cout << '\t';for (j = 0; j < m; j++)cout << j << '\t';cout << endl;for (i = 0; i < n; i++){cout << i << '\t';for (j = 0; j < m; j++){if (d[i][j] == 0x7ffff)d[i][j] = -1;cout << d[i][j] << '\t';}cout << endl;}return 0;
}

五、结果截图

动态规划法求解TSP问题 C++相关推荐

  1. 用动态规划法求解TSP问题

    一.求解TSP问题 1.问题描述 TSP问题(担货郎问题,旅行商问题)是指旅行家要旅行n个城市,要求各个城市经历且仅经历一次然后回到出发城市,并要求所走的路程最短 各个城市间的距离可以用代价矩阵来表示 ...

  2. 【动态规划法】求解TSP问题

    问题详情 求解下图所示的TSP问题,计算出所经过的城市编号以及最短路径值,城市代价矩阵如图所示: 求解思路 假设从顶点i出发,令d(i, V' )表示从顶点i出发经过V' 中各个顶点一次且仅一次,最后 ...

  3. 算法设计与分析实验二:动态规划法实现TSP问题和0/1背包问题

    [实验目的] 1.熟练掌握动态规划思想及教材中相关经典算法. 2.使用动态规划法编程,求解0/1背包问题和TSP问题. TSP问题 一.实验内容: TSP问题是指旅行家要旅行n个城市,要求每个城市经历 ...

  4. 回溯法解决tsp问题 matlab,回溯法求解tsp问题

    回溯法以这种工作方式递归地在解空间中搜索, 直至找到所 要求的解或解 空间中已无活结点时为止. 回溯法求解 TSP 问题,首先把所有的顶点的访问标志初始化为 0,...... 回溯法求解 TSP 问题 ...

  5. 模拟退火求解TSP问题

    模拟退火求解TSP问题 模拟退火算法步骤 1.寻找下一个解 2.计算下一个解的能量 3.决定是否接受这个解 4.降温 算法模板 double randfloat() {return rand()/(R ...

  6. python用动态规划求删除路径_Python | 动态规划求解TSP

    解题思路主要有两部分: i为当前节点(城市),S为还没有遍历的节点(城市集合),表示从第i个节点起,经历S集合中所有的点,到达终点的最短路径长度. 回溯找到最优的路径,需要将S集合一一对应一个数字(类 ...

  7. 贪心算法求解TSP问题(python)

    这里使用贪心算法求解TSP问题的python版本 # dist 为距离矩阵,start_index 为起始位置 def tsp_quick(dist: list, start_index: int): ...

  8. 基于贪心算法求解TSP问题(JAVA)

    前段时间在搞贪心算法,为了举例,故拿TSP来开刀,写了段求解算法代码以便有需之人,注意代码考虑可读性从最容易理解角度写,没有优化,有需要可以自行优化! 详细 代码下载:http://www.demod ...

  9. 人工蜂群算法求解TSP问题

    人工蜂群算法求解TSP问题 [标签] ABC TSP Matlab data:2018-10-19 author:怡宝2号 [总起]利用人工蜂群算法(Artificial Bee Colony Alg ...

最新文章

  1. rhel系统启动过程_Linux 的启动流程
  2. 【 Vivado 】时钟类型
  3. Akka2使用探索2(Con?guration)
  4. STM32使用IIC总线通讯协议在OLED屏幕上显示字符串、汉字、单总线获取DHT11模块温湿度并通过IIC显示到屏幕(软件IIC)
  5. Android聊天背景图片变形解决方案
  6. mysql连接编码设置_MySQL基础 - 编码设置
  7. JAVA utf8编码字符_Java中的UTF-8字符编码
  8. 原生Ajax的4大步骤分享
  9. springboot mybatis 事务_真香——Github上的优秀SpringBoot框架
  10. php环境搭建(php5.5.8+apache2.4)
  11. 图像语义分割(2)-DeepLabV1: 使用深度卷积网络和全连接条件随机场进行图像语义分割
  12. 如何:从代码创建 UML 类图(ZZ)
  13. AMI码及HDB3码的编译码程序设计
  14. 服务器断电后可以自动开机吗,想要服务器断电后自动开机,怎么设置?
  15. 特征值 是 系数行列式等于0时的 解
  16. 同步四进制加减法可逆计数器设计(D触发器+74153)
  17. 算法学习【1】三个空汽水瓶可以换一瓶汽水
  18. 【opencv】【python】libpng warning: iCCP: known incorrect sRGB profile 解决
  19. 案例3 淘宝点击关闭二维码
  20. 比较时间并计算时间差

热门文章

  1. WPF实现聚光灯查看内容特效
  2. 【电赛备考】基于STM32控制的可调PWM输出+LCD显示
  3. 邹碧华用“大数据”选拔优秀法官
  4. 18春学期《计算机应用基础》在线作业1,18春学期《计算机应用基础》在线作业1...
  5. 第一页搜索送别谷歌中国……
  6. 一年级计算机知识点总结,一年级《计算机基础》
  7. 店铺标题优化的注意事项
  8. 雷军:互联网创业的葵花宝典
  9. 使用“onmousedown”和“onmouseup”实现长按事件
  10. 月亮在没人看时存在吗?实在性和量子理论