POJ3411 狀態壓縮DP

2021-09-26 06:43:20 字數 1247 閱讀 1235

給n個城市,m條路,並給出m條路的資訊,每條資訊給出起點a終點b和中間節點c,有兩種付款方式

1、在中間節點c付款(就是可以提前交錢)-r(a,b);

2、到終點b付款-p(a,b)。

問1到n的最小花費

dp[i][s] 經過在集合s中的點到達i的最短花費

1、當s中沒有c時

dp[b][s∪b]=min(dp[i][s],dp[a][s]+p(a,b));

2、當s中有c時;

dp[b][s∪b]=min(dp[i][s],dp[a][s]+r(a,b),dp[a][s]+p(a,b));

先將路徑按起點城市的序號公升序排序;

首先如果一條路徑縮短,在最短花費的路上肯定不會經過終點;

在第一次遍歷中,可以求出城市號公升序經過的最小花費路徑;

每一次外層迴圈其實都是因為有迴路縮短了最小距離,因為迴路就會產生中間節點c,就可以使用第一種付費方案

每一次迴圈的最短迴路只會被更新一次,比如n1到n2到n1是一條迴路,縮短了n1到n3的值,因為是正序遍歷,所以n3到n1的迴路值後跟新,但是下次外迴圈時不會再縮短n1到n2到n1到n3這條迴路而是縮短n1到n3到n1到ni>3的迴路,所以最多需要n-1次外層迴圈!

#include

#include

#include

using namespace std;

#define inf 0x3f3f3f3f

int dp[15]

[1<<11]

;//到i點時經過了集合s

struct edge

}arr[15]

;int n,m;

intmain()

}int ans=inf;

for(s=

1;s<(1

<;s++

) ans=

min(ans,dp[n]

[s]);if

(ans==inf)

printf

("impossible\n");

else

printf

("%d\n"

,ans);}

return0;

}

POJ3411 狀態dp 鬆弛轉移

狀態轉移有兩種,一種是對於乙個狀態v找出這個狀態能夠來自哪些狀態u,然後更新v,但有時這種轉移方法不太好用,那麼考慮另一種轉移方法,對於乙個狀態u,我們考慮狀態u能夠影響的所有狀態v,然後不斷鬆弛,像spfa一樣.這題就是第二種轉移方法。另外inq標記陣列確實能節省時間,畢竟減少了節點入隊次數.這題...

POJ 狀態壓縮DP專題

poj3254 狀態壓縮dp的入門題。純粹的二維遞推,還可以通過滾動陣列優化,但這裡並不需要。include include include using namespace std int m,n,f 13 1 12 intmap 13 int in bool check int j,int k i...

poj 2411 狀態壓縮DP

用乙個vector容器來記錄當前狀態下有哪些狀態可以繼承。比如說vec i 裡面的所有的數代表當第一行為i狀態時,第二行的可行狀態。對於狀態i,其二進位制中0的地方表示為當前狀態為豎著的木板的下半部分。其二進位制中1的地方表示為當前狀態為橫著的木板或者豎著的木板的上半部分。include inclu...