hdu3538(最短哈密頓路徑+狀態壓縮)
阿新 • • 發佈:2019-02-09
終於是到了狀壓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;
}