Solve TSP with dynamic programming——动态规划解决旅行商(邮递员)问题

无向简单图的TSP算法

小规模精确解:

算法思想:

小规模精确解的算法中心思想是动态规划思想。

假设给定顶点集合V为{0,1,2,3,4,... .n}。由于图为无向完全图,我们可以很自然地将0视为输出的起点和终点。对于每个其他顶点i(除0之外),我们找到以0为起点,i为终点,且所有顶点恰好出现一次的最小成本路径。假设定义这条最小成本路径的成本为Cost(i),则相应TSP回路的Cost将是Cost(i)+ dist(i,0)其中dist(i,0)是从i到0的距离。最后,我们返回所有[cost(i)+ dist(i,0)]值,再从中选择最小值,此时该最小值也就是TSP的最优路径。而如何获得Cost(i)呢?那就是用动态规划算法来完成了:

定义CSi):

从集合S中访问每个顶点一次,且从0开始到i结束的最小成本路径的Cost

定义动态规划递归关系:

If size of S is 2, then S must be {0, i},
	C(S, i) = dist(1, i) 
Else if size of S is greater than 2.
	C(S, i) = min { C(S-{i}, j) + dis(j, i)} where j belongs to S, j != i and j != 0.

       所以,根据以上定义,求解TSP最优路径,等价于求解:

              min {C(S, i) + dist(i, 0)} for any i in |V – 0|

 

伪代码构造:

TSP(V, G)
// input: V is the vertex set, exactly i indicates ith vertex
// input: G is a matrix, which G[i][j] indicates the distance from ith node to jth one 
// output: the best optimal path of TSP
// output: the total cost of the path
	// define C a matrix
	// C[i][S]: C(S, i) be the cost of the minimum cost path visiting each vertex 
	// 			in set S exactly once, starting at 1 and ending at i
	C(|V|, (2^|V|, -1))
	// define path a matrix which the value records the last node of the current node
	paths(|V|, 2^|V|)
	min = INT_MAX
	for e in V-{0} do
		cost = dp_TSP(G, V, C, S, e, paths) + G[e][0]
		if cost < min do
			min = cost
			index = e
		endif
	endfor
	
	path = []
	S = [all node in V]
	do
		push index in path
		temp = index
		index = path[index][S]
		pop temp from S
	while index != -1
	push 0 in path
	
	return path.reverse, min
	
dp_TSP(G, V, C, S, i, paths)
// input: G is a matrix, which G[i][j] indicates the distance from ith node to jth one
// input: V is verties set
// input: C means C(S, i)
// input: S includes all nodes needed to visited once and only once 
// input: i, which indicate the end vertex in S
// input: records the last node of the current node in C(S, i)
// output: the value of C(S, i)
	if |S| == 2
		return G[0][i]
	endif
	if C(S, i) != -1
		return C(S, i)
	endif
	
	min = INT_MAX
	for j in S
		if j != {0} and j != e then
			value = C(S-{i}, j) + G[j][i]
			if value <= min then
				min = value
				index = j
			endif
		endif
	endfor
	
	C(S, i) = min
	path(S, i) = index
	return min

 

函数设计:

邻接矩阵读取函数设计:

      

TSP函数设计:

dp_TSP函数设计:

测试结果:

 

算法分析:

由于我们使用动态编程解决了这个问题,且动态编程方法包含子问题,子问题如下图显示:

如果我们求解递归方程,我们将得到总 个子问题,也就是。每个子问题将花费O(n)时间(找到剩余(n-1)个节点的路径)。因此总时间复杂度为。空间复杂度也是子问题的数量,即

虽然时间复杂度远小于On!),但仍然呈指数级。所需空间也是指数级的。因此,即使对于稍高数量的顶点,这种方法也是不可行的。由于在算法实现当中,用了long long int来作为S集合,所以超过64个节点的图就无法适用了。只能通过大规模近似求解。

 

完整代码:

#include <vector>
#include <iostream>

using namespace std;
typedef vector<vector<int> > G;
typedef vector<int> V;
G load_graph(int n);
void TSP(G& g, int n);
int dp_TSP(G& g, G& C, long long int S, int i, G& path);
V get_set(long long int S, int n);
int main(){
	int n;
	cin>> n;
	G g = load_graph(n);
	TSP(g, n);
	return 0;
}

G load_graph(int n){
	G g(n, V(n));
	for(int a=0; a<n; a++)
		for(int b=0; b<n; b++)
			scanf("%d", &g[a][b]);
			
	return g;
}
void printG(G& g){
	int n = g.size();
	int m = g[0].size();
	for(int a=0; a<n; a++){
		for(int b=0; b<m; b++)
			cout<< g[a][b]<< ' ';
		cout<< endl;
	}
}
void printV(V g){
	int n = g.size();
	for(int a=0; a<n; a++)
		cout<< g[a]<< ' ';
	cout<< endl;
}

void TSP(G& g, int n){
	// there are (2^n - 1) probable S for each i in C(S, i)
	int m = (1<<n);
	// define a term C(S, i) be the cost of the minimum cost path visiting each vertex 
	// in set S exactly once, starting at 1 and ending at i.
	G C(n, V(m, -1));
	// record the path
	G path(n, V(m, -1));
	// run the dynamic programming TSP algorithm
	// start at 0th node, and end at 0th node
	// find the minimum cost path with 1 as the starting point, i as the ending point
	int min = INT_MAX;
	int target = -1;
	for(int i=1; i<n; i++){
		// define S as a long long int variable, each ith bit record the existance of the ith node
		// initial S = 1<<n - 1, which means that S includes all node at first
		long long int S = (1<<n) - 1;
		// the cost of corresponding Cycle would be cost(i) + dist(i, 0)
		int cost = dp_TSP(g, C, S, i, path) + g[i][0];
		// the minimum of all [cost(i) + dist(i, 0)] values
		if(cost < min){
			min = cost;
			target = i;
		}
	}
	V output;
	long long int S = (1<<n) - 1;
	do{
		output.push_back(target);
		int temp = target;
		target = path[target][S];
		S = S^(1<<temp);
	}while(target != -1);
	//printG(C);
	cout<< min<< endl;
	for(int a=n-1; a>=0; a--)
		cout<< output[a]<< ' ';
	cout<< 0<< endl;
}

int dp_TSP(G& g, G& C, long long int S, int i, G& path){
	V set = get_set(S, g.size());
	/*
	If size of S is 2, then S must be {0, i},
		C(S, i) = dist(1, i) 
	Else if size of S is greater than 2.
		C(S, i) = min { C(S-{i}, j) + dis(j, i)} where j belongs to S, j != i and j != 0.
	*/
	if(set.size()==2){
		path[i][S] = 0;
		return g[0][i];
	}
	if(C[i][S] != -1)
		return C[i][S];
	int min = INT_MAX, index = -1;
	long long int new_S = S^(1<<i);
	for(int a=0; a<set.size(); a++){
		int j = set[a];
		if(j!=i && j!=0){
			int result = dp_TSP(g, C, new_S, j, path) + g[j][i];
			//cout<< i<< ' '<< result<< ' '<< j<< endl;
			if(result < min){
				min = result;
				index = j;
			}
		}
	}
	C[i][S] = min;
	path[i][S] = index;
	//cout<< i<< ' '<< index<< "dad"<< endl;
	return min;
}

V get_set(long long int S, int n){
	V set;
	for(int a=0; a<n; a++)
		if(S & (1<<a))
			set.push_back(a);
			
	return set;
}

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值