1. 程式人生 > >hdu3538(最短哈密頓路徑+狀態壓縮)

hdu3538(最短哈密頓路徑+狀態壓縮)

終於是到了狀壓DP圖論,初心就是為了解決圖論。

題意:

給個圖,給出m個限制,a,b b這個點必須出現在a之後。 問從1出發的最短哈密頓路徑(從起點出發,經過所有的點一次)

概述:

從本質理解狀壓DP, DP[state] [ u ] 表示已經走過的狀態為state , 且當前的節點處於 u ,那麼刷表拓展,找出u節點的下一個合法節點,並且必須滿足 state 和 下個節點的關係 ,也就是未經過的關係

思路:

限制條件是 a必須在 b 之前出現,那麼開一個數組 bef[b ] = bef[b] | (1 < < a) ,這樣b 的所以限制條件,都表示在 befb] 裡面 , 用二進位制形式呈現, 遞推的時候,我們在拓展下個節點 v 的時候,就可以用這樣 if( bef[v] == state & bef[v] ) ? 這個語句的意思是 ,bef[v] 存在的位置,state也必須存在,那麼就滿足了限制條件,再拓展。

程式碼:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <iostream>
#include <algorithm>
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = 25;

int mp[maxn][maxn];
int dp[(1<<22)][maxn];
int bef[maxn];

int main()
{
    int n,m;
    while
(scanf("%d%d",&n,&m) != EOF) { memset(bef,0,sizeof(bef)); for(int i=0; i<n; i++) for(int j=0; j<n; j++) { scanf("%d",&mp[i][j]); } while(m--) { int a,b; scanf("%d%d",&a,&b); bef[b]|=(1
<<a); } for(int i=0; i<(1<<n); i++) for(int j=0; j<n; j++) dp[i][j] = inf; dp[1][0] = 0; for(int state = 1 ; state < (1<<n); state++) { for(int i=0; i<n; i++) // 用過的 { if(!(state & (1<<i))) continue; if(dp[state][i] == inf) continue; for(int j=0; j<n; j++) { if(mp[i][j] == -1 || (state&(1<<j))>0 || bef[j] != (state&bef[j])) continue; int nsta = state | (1<<j); dp[nsta][j] = min(dp[nsta][j], dp[state][i] + mp[i][j]); } } } int ans = inf; for(int i=0; i<n; i++) { ans = min(ans, dp[(1<<n)-1][i]); } if(ans == inf) { puts("-1"); } else printf("%d\n",ans); } return 0; }