皇宮看守(樹形dp)
阿新 • • 發佈:2020-12-02
題解:
不同於戰略遊戲那道題要求每邊有人看守,即只能靠自己或者靠兒子,本題要求每個點有人看守,即對於點root可以靠自己靠兒子或靠父親
設dp[root][0/1/2]表示0靠自己1靠爸爸2靠兒子
root靠自己可以從兒子的三種狀態轉移,但是要加上自己設看守的費用
root靠爸爸可以讓兒子靠自己或者靠兒子的兒子(好爸爸)
注意這裡!root靠兒子必須要有一個兒子靠自己,其餘兒子靠自己或者靠兒子的兒子,實現見程式碼
特別的,根結點不能靠爸爸,葉子結點不能靠兒子
AC_Code:
1 #include <bits/stdc++.h> 2 using namespacestd; 3 typedef long long ll; 4 const int maxn = 1500+10; 5 const int mod = 1e9+7; 6 const int inf = 0x3f3f3f3f; 7 8 int cnt[maxn],dp[maxn][3], son[maxn][maxn], k[maxn],fa[maxn]; 9 int n,x; 10 11 //dp[i][0]:靠自己可以看守到i所需的最小花費 12 //dp[i][1]:靠爸爸可以看守到i所需的最小花費 13 //dp[i][2]:靠兒子可以看守到i所需的最小花費 14 15 void dfs(introot){ 16 if( !cnt[root] ){ //葉子節點 17 dp[root][0] = k[root]; 18 dp[root][1] = 0; 19 dp[root][2] = inf; 20 return ; 21 } 22 23 for(int i=1;i<=cnt[root];i++){ 24 dfs( son[root][i] ); 25 } 26 dp[root][0] = k[root]; 27 int f = 0; 28for(int i=1;i<=cnt[root];i++){ 29 dp[root][0] += min(dp[son[root][i]][1], min(dp[son[root][i]][0], dp[son[root][i]][2])); 30 dp[root][1] += min(dp[son[root][i]][0], dp[son[root][i]][2]); 31 dp[root][2] += min(dp[son[root][i]][0], dp[son[root][i]][2]); 32 33 if( dp[son[root][i]][0]<=dp[son[root][i]][2] ){//標記有沒有哪個兒子靠自己比靠兒子的花費少的 34 f = 1; 35 } 36 } 37 if( !f ){//若沒有 38 int minn = 0x3f3f3f3f; 39 for(int i=1;i<=cnt[root];i++){ 40 minn = min(minn, dp[son[root][i]][0]-dp[son[root][i]][2]); 41 } 42 dp[root][2] += minn; 43 } 44 } 45 46 int main() 47 { 48 memset(dp,0,sizeof(dp)); 49 scanf("%d",&n); 50 for(int i=1;i<=n;i++){ 51 int x; scanf("%d",&x); 52 scanf("%d%d",&k[x],&cnt[x]); 53 for(int j=1;j<=cnt[x];j++){ 54 scanf("%d",&son[x][j]); 55 fa[son[x][j]] = x; 56 } 57 } 58 for(int i=1;i<=n;i++){ 59 if( !fa[i] ){ 60 dfs(i); 61 int ans = min(dp[i][0], dp[i][2]); 62 printf("%d\n",ans); 63 break; 64 } 65 } 66 return 0; 67 }