1. 程式人生 > >HDU 3001(狀態壓縮DP)

HDU 3001(狀態壓縮DP)

狀態壓縮 printf pri names urn 壓縮 puts -1 路徑

題意:遍歷所有的城市的最短路徑,每個城市最多去兩遍。將城市的狀態用3進制表示。

狀態轉移方程為 dp[NewS][i]=min( dp[NewS][i],dp[S][j]+dis[i][j])

S表示遍歷點的狀態,i表示到達第i個城市。

在到第i個城市的時候看是否存在一個j城市的路徑,然後再從j到i更短。

#include <algorithm>
#include <cstdio>
#include <cstring>

#define Max 1000001
#define MAXN 150000
#define MOD 100000000
#define rin freopen("in.txt","r",stdin)
#define
rout freopen("1.out","w",stdout) #define Del(a,b) memset(a,b,sizeof(a)) #define INF 0x1f1f1f1f using namespace std; typedef long long LL; int edge[11][11]; int n, m; int tri[] = { 0, 1, 3, 9, 27, 81, 243, 729, 2187, 6561, 19683, 59049 }; int dp[59050][11]; int dig[59050][11]; void Init() { Del(dp, INF); Del(edge, INF);
for (int i = 1; i <= n; i++) { dp[tri[i]][i] = 0; } } void Solve() { int ans = INF; for (int S = 0; S < tri[n+1]; S++) { int flag = 1; for (int i = 1; i <= n; i++) { if (dig[S][i] == 0) flag = 0; if (dp[S][i] == INF)
continue; for (int j = 1; j <= n; j++) { if (i == j) continue; if (edge[i][j] == INF || dig[S][j] == 2) continue; int NewS = S + tri[j]; dp[NewS][j] = min(dp[NewS][j], dp[S][i] + edge[i][j]); } } if (flag) { for (int j = 1; j <= n; j++) ans = min(ans, dp[S][j]); } } if (ans == INF) { puts("-1"); } else { printf("%d\n", ans); } return; } int main() { //rin; for (int i = 0; i < 59050; i++) { int t = i; for (int j = 1; j <= 10; j++) { dig[i][j] = t % 3; t /= 3; if (t == 0) break; } } while (scanf("%d%d", &n, &m) != EOF) { Init(); for (int i = 0; i < m; i++) { int a, b, c; scanf("%d%d%d", &a, &b, &c); if (c < edge[a][b]) edge[a][b] = edge[b][a] = c; } Solve(); } return 0; }

HDU 3001(狀態壓縮DP)