1. 程式人生 > >HDU-1561-樹形dp+背包

HDU-1561-樹形dp+背包

NPU gree 樹形dp sample sin dfs scrip ria code

The more, The Better

Time Limit: 6000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 9169 Accepted Submission(s): 5343


Problem Description ACboy很喜歡玩一種戰略遊戲,在一個地圖上,有N座城堡,每座城堡都有一定的寶物,在每次遊戲中ACboy允許攻克M個城堡並獲得裏面的寶物。但由於地理位置原因,有些城堡不能直接攻克,要攻克這些城堡必須先攻克其他某一個特定的城堡。你能幫ACboy算出要獲得盡量多的寶物應該攻克哪M個城堡嗎?

Input 每個測試實例首先包括2個整數,N,M.(1 <= M <= N <= 200);在接下來的N行裏,每行包括2個整數,a,b. 在第 i 行,a 代表要攻克第 i 個城堡必須先攻克第 a 個城堡,如果 a = 0 則代表可以直接攻克第 i 個城堡。b 代表第 i 個城堡的寶物數量, b >= 0。當N = 0, M = 0輸入結束。

Output 對於每個測試實例,輸出一個整數,代表ACboy攻克M個城堡所獲得的最多寶物的數量。

Sample Input 3 2 0 1 0 2 0 3 7 4 2 2 0 1 0 4 2 1 7 1 7 6 2 2 0 0

Sample Output 5 13

Author 8600     註意到寶物之間的關系可以用一顆有向樹來表示,0號節點就是根,用f[i][j]表示由i號節點延伸j個節點(包括i在內)可以達到的最大價值,對於當前節點,對他的每一個兒子跑一遍背包,枚舉當前兒子包含的節點數k,那麽之前所有兒子包含的節點數就是j-k(算上父親),最後答案就是f[0][m+1];     註意節點數j要降序枚舉否則更新後的數組會影響後面的狀態。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define inf 0x3f3f3f3f
 4
int first[220],tot; 5 int f[210][210]; 6 struct Edge 7 { 8 int v,next; 9 }e[500]; 10 void add(int u,int v) 11 { 12 e[tot].v=v; 13 e[tot].next=first[u]; 14 first[u]=tot++; 15 } 16 int b[220],M,N; 17 int dfs(int u) 18 { 19 f[u][1]=b[u]; 20 int s=1; 21 for(int i=first[u];~i;i=e[i].next){ 22 int v=e[i].v; 23 int son=dfs(v); 24 s+=son; 25 for(int j=M+1;j>=1;--j){ 26 for(int k=1;j-1>=k&&k<=son;++k){ 27 f[u][j]=max(f[u][j],f[u][j-k]+f[v][k]); 28 } 29 } 30 } 31 return s; 32 } 33 int main() 34 { 35 int n,m,i,j,k; 36 while(cin>>n>>m&&(n||m)){ 37 N=n,M=m; 38 memset(f,0,sizeof(f)); 39 memset(first,-1,sizeof(first)); 40 tot=0; 41 for(i=1;i<=n;++i){ 42 scanf("%d%d",&k,&b[i]); 43 add(k,i); 44 } 45 dfs(0); 46 //cout<<f[1][1]<<‘ ‘<<f[2][1]<<‘ ‘<<f[3][1]<<endl; 47 cout<<f[0][m+1]<<endl; 48 } 49 return 0; 50 }

HDU-1561-樹形dp+背包