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
中文題沒啥好解釋的了。
方法:樹形DP+背包。其實就是一個在樹上完成的背包問題。f[x][i]表示攻打i個城堡,第i個城堡是x。F[j]就表示攻打j個城堡所獲得的寶物數量。F[j] =max(F[j],F[j-k]+f[num[x][i]][[k]]).不做過多贅述了。上代碼。
#include<cstdio>#include<cstring>#include<vector>#include<iostream>#define S 210using namespace std;int f[S][S];int n ,m;int tre[S] ,flag[S] ,F[S];vector<int> num[S];void deal(int x){int i ,j ,k;flag[x] = 1;for(i = 0;i < num[x].size();i++){if(flag[num[x][i]]==0){deal(num[x][i]);}}memset(F,0,sizeof(F));for(i = 0;i < num[x].size();i++){for(j = m;j>=0;j--){for(k = 0;k<=j;k++){if(F[j] < F[j-k] + f[num[x][i]][k]){F[j] = F[j-k] + f[num[x][i]][k];}}}}for(i = 1;i <= m;i++){f[x][i] = F[i-1] + tre[x];}};int main(){int i ,j;int a ,b;while(scanf("%d%d",&n,&m),m+n!=0){for(i = 0;i<=n;i++){num[i].clear();}for(i = 1;i<=n;i++){scanf("%d%d",&a,&b);tre[i] = b;num[a].push_back(i);}tre[0] = 0;m++;memset(flag,0,sizeof(flag));deal(0);printf("%d\n",f[0][m]);}return 0;}