hdu 5418 Victor and World (状压dp)

Posted jpphy0

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了hdu 5418 Victor and World (状压dp)相关的知识,希望对你有一定的参考价值。

问题

分析

参考

状态定义

  • d p [ s ] [ i ] dp[s][i] dp[s][i] s s s 为曾到达过的城市的下标的映射, i i i 为最后一个到达的城市的下标
  • 状态转移
    d p [ s ∣ ( 1 < < ( j − 1 ) ) ] [ j ] = m a x ( d p [ s ∣ ( 1 < < ( j − 1 ) ) ] [ j ] , d p [ s ] [ i ] + g [ i ] [ j ] ) dp[s | (1<< (j-1))][j]=max(dp[s | (1<< (j-1))][j],dp[s][i]+g[i][j]) dp[s(1<<(j1))][j]=max(dp[s(1<<(j1))][j]dp[s][i]+g[i][j])
  • g [ i ] [ j ] ) g[i][j]) g[i][j]) i i i j j j 之间的最优解,通过 F l o y d Floyd Floyd 算法求解
  • 在扩展过程中,不必保证每次扩展的路径是在集合内部,否则复杂度较高 O ( n 3 ⋅ 2 n ) O(n^3\\cdot 2^n) O(n32n) ~ O ( n 4 ⋅ 2 n ) O(n^4\\cdot 2^n) O(n42n)

代码

集合外扩展【265MS】

/* hdu 5418 Victor and World 状压dp */
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int MXS = (1<<16)+5;
const int MXN = 20;
int N, M, g[MXN][MXN], dp[MXS][MXN], c[MXS];
int main(){
	int t, T = 0, S, u, v, w;
	for(int i = 0; i < 16; ++i) c[1<<i] = i+1;
	scanf("%d", &t);
	while(t--){
		memset(g, inf, sizeof g);
		memset(dp, inf, sizeof dp);
		scanf("%d%d", &N, &M);
		S =  (1<<N)-1;		
		for(int i = 1; i <= N; ++i) g[i][i] = 0;
		while(M--){
			scanf("%d%d%d", &u, &v, &w);
			g[u][v] = g[v][u] = min(g[u][v], w);
		}
		for(int i = 1; i <= N; ++i) // Floyd
			for(int j = 1; j <= N; ++j)
				for(int k = 1; k <= N; ++k) 
					g[k][i] = min(g[k][i], g[j][i]+g[j][k]);

		dp[1][1] = 0;
		for(int s = 1; s < S; ++s){
			for(int lst=c[-s&s], j = s; j > 0; j &= j-1, lst = c[-j&j]){//枚举集合元素
				if(dp[s][lst] == inf) continue; // 未出现的状态
				for(int cs, nxt, d = S^s; d > 0; d &= d-1){ // 枚举集合外的扩展点
					nxt = c[-d&d], cs = s|(-d&d);
					dp[cs][nxt] = min(dp[cs][nxt], dp[s][lst]+g[lst][nxt]);			
				}
			}
		}
		for(int i = 2; i <= N; ++i)
			if(dp[S][1] > dp[S][i]+g[1][i]) dp[S][1] = dp[S][i]+g[1][i];
		printf("%d\\n", dp[S][1]);
	}
    return 0;
}

集合内扩展【530MS】

/* hdu 5418 Victor and World 状压dp */
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf = 0x7f7f7f7f;
const int MXS = (1<<16)+5;
const int MXN = 20;
int N, M, mp[MXN][MXN], dp[MXS][MXN], c[MXS];
int main(){
	int t, T = 0, S, u, v, w;
	for(int i = 0; i < 16; ++i) c[1<<i] = i+1;
	scanf("%d", &t);
	while(t--){
		scanf("%d%d", &N, &M);
		S =  (1<<N)-1;
		memset(mp, 0x7f, sizeof mp), memset(dp, inf, sizeof dp);
		while(M--){
			scanf("%d%d%d", &u, &v, &w);
			mp[u][v] = mp[v][u] = min(mp[u][v], w);
		}
		dp[1][1] = 0;
		for(int s = 1; s < S; ++s){
			for(int lst=c[-s&s], j = s; j > 0; j &= j-1, lst = c[-j&j]){
				if(dp[s][lst] == inf) continue;
				for(int cs, nxt, d = S^s; d > 0; d &= d-1){
					nxt = c[-d&d], cs = s|(-d&d);
					if(mp[nxt][lst] == inf) continue;
					dp[cs][nxt] = min(dp[cs][nxt], dp[s][lst]+mp[lst][nxt]);
					for(int org = c[-s&s], g = s; g > 0; g &= g-1, org = c[-g&g]){
						if(mp[nxt][org] == inf) continue;
						dp[cs][org] = min(dp[cs][org], dp[cs][nxt]+mp[nxt][org]);
					}
				}
			}
		}
		for(int i = 2; i <= N; ++i){
			if(mp[1][i] == inf) continue;
			if(dp[S][1] > dp[S][i]+mp[1][i]) dp[S][1] = dp[S][i]+mp[1][i];
		}
		printf("%d\\n", dp[S][1]);
	}
    return 0;
}

以上是关于hdu 5418 Victor and World (状压dp)的主要内容,如果未能解决你的问题,请参考以下文章

hdu 5418 Victor and World (状压dp)

BestCoder Round #52 (div.2) HDU 5418 Victor and World (DP+状态压缩)

HDOJ 5418 Victor and World 状压DP

HDU Victor and World (最短路+状态压缩)

HDU5421Victor and String(回文树)

HDU - 5421:Victor and String (回文树,支持首尾插入新字符)