位运算_二进制状态压缩DP_CH0103_最短Hamilton路径

版权声明:本文为博主原创作品, 转载请注明出处! https://blog.csdn.net/solider98/article/details/83210638

点此进入题目页面

思路分析:

    本题是典型的二进制状态压缩DP问题(为方便叙述, 约定点i表示编号为i的点, 整数的最低位为第0位), 设F[i][j]表示从点0的点出发到点j, 且经过点的状态为i的最短路径长(路径上所有边的权值之和), 是如何表示经过点的状态的? 如果i的第k(k >= 0)位为1那么该路径经过点k, 为0则不经过点k, 最终需求得F[(1 << n) - 1][n - 1] 欲求F[i][j], 可考察其对应路径的倒数第2个顶点(如果存在)t, 初始化F[1][0]为0, 下面给出状态转移方程:

注意: i & ~(1 << j)表示将i的第j位赋0得到的值, weight[t][j]表示边<t, j>(如果存在)的权值

F[]i][j] = min{ F[i & ~(1 << j)][t] + weight[t][j] | t \neq j, i 的第j位为1, i的第t位为1,  存在边<i, j>} 

下面给出AC代码:

//CH0103_最短Hamilton路径
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAX = 20; 
int F[1 << MAX][MAX], weight[MAX][MAX];
int main(){
	int n;
	scanf("%d", &n);
	for(int i = 0; i < n; ++i)
		for(int j = 0; j < n; ++j) scanf("%d", &weight[i][j]);
	memset(F, 0x3f, sizeof(F)), F[1][0] = 0;//前者将F中所有元素初始化为正无穷大, 是必要的 
	for(int i = 2; i < (1 << n); ++i)
		for(int j = 0; j < n; ++j)
			if((i >> j) & 1)
				for(int t = 0; t < n; ++t)
					if(j != t && (i >> t) & 1)
						F[i][j] = min(F[i][j], F[i & ~(1 << j)][t] + weight[t][j]);
	cout << F[(1 << n) - 1][n - 1] << endl;
	return 0;
} 

值得指出的是, 对于F[i][j], 上述算法递增的计算考察i值, 也即考察当前问题时, 所有的子问题(对应更小的i值)已经求解

对于上述算法的时间复杂度, 显然为O(2^{n}n^{2})

猜你喜欢

转载自blog.csdn.net/solider98/article/details/83210638