【狀壓dp】【POJ2288】Islands and Bridges【Hamilton路】
阿新 • • 發佈:2018-11-19
題意:
給你一張圖,找到一條Hamilton路,要求從其中一個節點出發,遍歷圖中所有節點一遍。
這樣一條路徑的權值計算為三部分的累加。
第一部分:這條路徑上所有節點的權值之和。
第二部分:這條路徑上相鄰兩點的乘積。
第三部分:這條路徑上相鄰三個點的乘積。(如果三個點互相直接相連)
如,a1、a2、a3、a4這四個點形成的一條路徑,第一部分為w1+w2+w3+w4,第二部分為w1*w2+w2*w3+w3*w4,第三部分為如果a1和a3直接相連,a2和a4直接相連,則為a1*a2*a3+a2*a3*a4。
要求輸出按照上述計算方法所能找到的最大的Hamilton路,並且輸出這條路的個數,n <= 13。
思路:
因為這樣一條路徑的更新涉及到最後兩個點,所以三維dp肯定要記錄最後兩個節點了,然後第一維用狀態壓縮記錄當前走過的節點,第二維記錄這條路徑最後一個節點,第三維記錄倒數第二個節點。
dp[i][j][k]表示當前狀態為i,最後一個節點為j,倒數第二個節點為k。
然後dp[i][j][k]去更新dp[i|(1<<p)][p][j],四個for迴圈結束本題。
本題細節較多,比如num會爆int,可能會出現0 x這樣的答案等等,詳見程式碼。
總結:
此類狀壓dp,大都較為相似,先開一維記錄狀態,再根據題意,看需要記錄一個數值,多記錄一個數值則需要多開一維狀態。
程式碼:
#include <cstdio> #include <iostream> #include <cstring> #include <algorithm> #define rep(i,a,b) for(int i = a; i <= b; i++) using namespace std; typedef long long ll; int n,m; int a[20]; int w[20][20]; int dp[1<<13][15][15]; ll way[1<<13][15][15]; void solve() { memset(dp,-1,sizeof dp); rep(i,0,n-1) rep(j,0,n-1) if(w[i][j]) dp[(1<<i)|(1<<j)][i][j] = a[i]+a[j]+a[i]*a[j], way[(1<<i)|(1<<j)][i][j] = 1; rep(i,0,(1<<n)-1) rep(j,0,n-1) //最後一個 if(i&(1<<j)) rep(k,0,n-1) //倒數第二個 if((i&(1<<k)) && w[j][k] && dp[i][j][k] != -1){ // cout << "$$$$" << endl; rep(h,0,n-1)//倒數第三個 if(!(i&(1<<h)) && w[h][j]) { int ans = dp[i][j][k]+a[j]*a[h]+a[h]; if(w[h][k]) ans += a[k]*a[h]*a[j]; if(ans == dp[i^(1<<h)][h][j]) way[i^(1<<h)][h][j]+=way[i][j][k]; else if(ans > dp[i^(1<<h)][h][j]){ dp[i^(1<<h)][h][j] = ans; way[i^(1<<h)][h][j] = way[i][j][k]; } } } int maxn = 0; ll num = 0; rep(i,0,n-1) rep(j,0,n-1) if(w[i][j]){ if(maxn < dp[(1<<n)-1][i][j]) maxn = dp[(1<<n)-1][i][j], num = way[(1<<n)-1][i][j]; else if(maxn == dp[(1<<n)-1][i][j]) num += way[(1<<n)-1][i][j]; } printf("%d %lld\n",maxn,num/2); } int main() { int T; scanf("%d",&T); while(T--) { memset(w,0,sizeof w); memset(way,0,sizeof way); scanf("%d%d",&n,&m); rep(i,0,n-1) scanf("%d",&a[i]); if(n == 1) { printf("%d 1\n", a[0]); continue ; } rep(i,1,m) { int x,y; scanf("%d%d",&x,&y); x--, y--; w[x][y] = 1, w[y][x] = 1; } solve(); } return 0; } /* dp[1<<13][15][15]:last next */