动态规划解决TSP问题(代码可运行)

一、Tsp问题

假设有一个旅行商人要拜访n个城市,他必须选择所要走的路径,路径的限制是每个城市只能拜访一次,而且最后要回到原来出发的城市。路径的选择目标是要求得的路径路程为所有路径之中的最小值。

先生成相互距离二维表

image

二、动态规划

 设s, s1, s2, …, sp, s是从s出发的一条路径长度最短的简单回路,假设从s到下一个城市s1已经求出,则问题转化为求从s1到s的最短路径,显然s1, s2, …, sp, s一定构成一条从s1到s的最短路径,所以TSP问题是构成最优子结构性质的,用动态规划来求解也是合理的。

image

三、编程思路

 

所谓状态压缩,就是利用二进制以及位运算来实现对于本来应该很大的数组的操作。而求解动态规划问题,很重要的一环就是状态的表示,一般来说,一个数组即可保存状态。但是有这样的一些题目,它们具有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

https://cloud.tencent.com/developer/article/1103366

https://www.jianshu.com/p/30ba1d66c729

  • 19
    点赞
  • 179
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值