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<<(j−1))][j]=max(dp[s∣(1<<(j−1))][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(n3⋅2n) ~ O ( n 4 ⋅ 2 n ) O(n^4\\cdot 2^n) O(n4⋅2n)
代码
集合外扩展【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