1. 程式人生 > >hdu1561The more, The Better(樹形背包)

hdu1561The more, The Better(樹形背包)

允許 ++ ont cstring accepted ted 測試 str 開始

The more, The Better

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


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

code

第一道樹形背包題!

寫的題解很啰嗦,是我第一次的時有的疑問。

 1 /*
 2 hdu 1561 : The more,the better 
 3 
 4 dp[i][j] : 當前i節點及其子樹下選擇j個城市的最大值為dp[i][j];
 5 
 6 這一道題目註意建立了一個超級根節點0,
 7 任何點都要先拿0才可以。所以後面很多地方都是m+1 
 8 
 9 下面的轉移方程中有一句dp[u][j] = max(dp[u][j],dp[u][j-k]+dp[v][k]);
10 那麽可能就有疑問了:dp[u][j-k]+dp[v][k] 
11 從子樹v中取出k個點 與 根樹u中取出的j-k個點 合並成 從根樹中取j個點 12 仔細讀完就會發現問題了:既然v是u的子樹,那麽dp[v][k]會不會和dp[u][j-k]沖突呢 13 即:從子樹v中取出K個點,然後在u中取出j-k個點,會不會v中的點又在u個點中出現了呢 14 答案是不會的。 15 因為遍歷每個從u遍歷v,遞歸求解出dp[v]的值,用v來更新u,也就是說在以前是沒有便利到v 16 的,所以dp[u]中也不是由v更新的,所以dp[u][j-k]的點沒有子樹v中的點 17 18 然後註意轉移時m一定要逆序,和01背包相似 19 01:背包加入一個物品,然後用這個物品更新 20 f[v],f[v]=max(f[v],f[v-Tiji[i]]+jiazhi[i]) 21 樹上的相似:加入一個物品,即遍歷到v,然後用這個物品更新 22 dp[v] = max(dp[v],dp[v-k]+(新節點)子樹大小為k的最大價值) //後面的那個遞歸求解。 23 然後由於樹形背包的限制(拿v之前先拿u)加了一維。 24 25 26 */ 27 28 #include<cstdio> 29 #include<algorithm> 30 #include<cstring> 31 32 using namespace std; 33 34 const int MAXN = 210; 35 const int MAXM = 50010; 36 37 struct Edge{ 38 int to,nxt; 39 }e[MAXM]; 40 int head[MAXM],tot; 41 int val[MAXN],dp[MAXN][MAXN]; 42 43 inline int read() { 44 int x = 0,f = 1;char ch = getchar(); 45 for (; ch<0||ch>9; ch = getchar()) 46 if (ch==-) f = -1; 47 for (; ch>=0&&ch<=9; ch = getchar()) 48 x = x*10+ch-0; 49 return x*f; 50 } 51 inline void add_edge(int u,int v) { 52 e[++tot].to = v,e[tot].nxt = head[u],head[u] = tot; 53 } 54 inline void init() { 55 memset(head,0,sizeof(head)); 56 memset(dp,0,sizeof(dp)); 57 tot = 0; 58 } 59 void dfs(int u,int m) { 60 dp[u][1] = val[u]; 61 for (int i=head[u]; i; i=e[i].nxt) { 62 int v = e[i].to; 63 dfs(v,m); 64 for (int j=m; j>=2; --j) 65 for (int k=0; k<j; ++k) 66 dp[u][j] = max(dp[u][j],dp[u][j-k]+dp[v][k]); 67 } 68 } 69 int main() { 70 int n,m; 71 while (scanf("%d%d",&n,&m)!=EOF && n+m!=0) { 72 init(); 73 for (int u,v,i=1; i<=n; ++i) { 74 u = read(),v = read(); 75 val[i] = v; 76 add_edge(u,i); 77 } 78 val[0] = 0; // 超級根節點權值為0 79 dfs(0,m+1); // 從0開始 80 printf("%d\n",dp[0][m+1]); 81 } 82 return 0; 83 }

hdu1561The more, The Better(樹形背包)