HDU 1561 The more, The Better - 依賴揹包+樹形dp基礎

/*
	http://acm.hdu.edu.cn/showproblem.php?pid=1561 The more, The Better
	依賴揹包 -> 樹形dp
題意: 給一個樹形結構,問最多拿max個城市 ,能獲得的最大價值多少,拿下面的一定要先拿上面的。
解題思路:
定義狀態dp[i][j] : 當前i節點及其子樹下最多選擇j個城市的最大值爲dp[i][j];
我們考慮到特殊狀態:i節點下沒有孩子那麼dp[i][2,3,4,5...]均爲-1(因爲多選總比少選好,並且選擇完後城市總是有剩餘)

1. 判斷當前節點P有沒有孩子,如果有則令當前節點爲P重複(1)操作,如果沒有則到(2)操作;
2. 將當前節點P的狀態更新到期父節點上,
更新操作爲dp[P'father][i] = max(dp[P'father][i], dp[P'father][j]+dp[P][k])    (j + k = i ,j>0,k>0,2<=i<=max_cost,對於每一個i遍歷每一種(j,k)組合)
這裏的dp[P'father][j] j個城市一定是沒有包括P城市的其他j個城市的最大值 
直到遍歷到root節點即可(dp[0][i])
3.輸出dp[0][max_cost]
max_cost 爲題目中所給出的最多取幾個城市

7 4
2 2
0 1
0 4
2 1
7 1
7 6
2 2
									[i]:v 表示 第i個節點的價值爲v; [0]root沒有價值相當於[0]:0
                   [0]root
                 /         \
            [2]:1          [3]:4
         /    |   \   
   [1]:2   [4]:1   [7]:2
                  /     \
                [5]:1  [6]:6



*/

#include <cmath>
#include <queue>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define CLR(c,v) memset(c,v,sizeof(c))

template <typename _T>
_T Max(_T a, _T b){
	return (a>b)?(a):(b);
}
template <typename _T>
_T Max(_T a, _T b,_T c){
	return (a>Max(b,c))?(a):(Max(b,c));
}
template <typename _T>
_T Min(_T a, _T b){
	return (a<b)?(a):(b);
}
template <typename _T>
_T Min(_T a, _T b,_T c){
	return (a<Min(b,c))?(a):(Min(b,c));
}

const int inf  = -(1<<30);
const int INF  =  (1<<30);
const int M    =  2e2 + 10;

vector <int > list[M];
int dp[M][M];
int n,max_cost;

void dfs(int father){
	for (int i = 0 ; i < list[father].size() ; i++){
		int child = list[father][i]; // 子節點
		if(list[child].size() > 0) 
			dfs(child);
		for(int j = max_cost ; j > 1 ; j--){// 保證從父節點開始,至少取j個城市,j>1 至少包括了這個父節點
			for(int k = 1 ; k < j ; k++ ){ //  遍歷每一種 k + j-k == j組合
				dp[father][j] = Max(dp[father][j] ,dp[father][k] +  dp[child][j-k]);
			}
		}
	}
}

int main(){
	freopen("in.txt", "r", stdin);
	while(cin >> n >> max_cost , n&&max_cost){
		max_cost ++; // 因爲數據給出的是森林,我們加入一個root節點,因此相當於允許多拿一個城市。
		CLR(dp,0);
		for(int i = 1 ; i <= n ; i ++){
			int a , b;
			cin >> a >> b;
			list[a].push_back(i);
			for(int j = 1 ; j <= max_cost ; j++)
				dp[i][j] = b;  // 初始化時,每個節點,所有狀態都是拿自己一個
		}
		dfs(0);
		for(int i = 0 ; i <= n ; i ++)
			list[i].clear();
		cout << dp[0][max_cost] << endl;
	}
	return 0;
}




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章