HDOJ (HDU) 1561 The more, The Better (树形DP)

HDOJ (HDU) 1561 The more, The Better (树形DP)

题意:中文题。。
解题思路:求最优解,考虑dp。树形dp,转换成有依赖的分组背包
dp[u][i]表示u子树中取i个物品,能获得的的最大价值是多少。cnt[u]数组表示u子树的大小,即背包的容量,cnt数组可以通过递归计算子树后不断增大。设V为U的儿子,取到v必须取到u。所以先不考虑将u物品放入背包中,而是将所有子树组成的背包先计算好后,再将u放入进去,体积加一。
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std ;

int dp[222][222] , cnt[222] , r[222] ;
struct Edge
{
	int t , next ;
} edge[222] ;
int head[222] , tot ;

void new_edge ( int a , int b )
{
	edge[tot].t = b ;
	edge[tot].next = head[a] ;
	head[a] = tot ++ ;
}

void init ( int n )
{
	int i , j ;
	for ( i = 0 ; i <= n ; i ++ )
		for ( j = 0 ; j <= n ; j ++ )
			dp[i][j] = 0 ;
	for ( i = 0 ; i <= n ; i ++ ) head[i] = -1 , cnt[i] = 0 ;
	tot = 0 ;
}

void dfs ( int u )
{
	if ( head[u] == -1 ) 
	{
		dp[u][1] = r[u] ;
		cnt[u] = 1 ;
		return ;
	}
	int i , j , k ;
	for ( i = head[u] ; i != -1 ; i = edge[i].next )
	{
		int v = edge[i].t ;
		dfs ( v ) ;
		cnt[u] += cnt[v] ;//树的大小通过子树的增加不断变大
		for ( j = cnt[u] ; j >= 1 ; j -- )//背包从大到小枚举,保证先用较小的更新较大的,这样便可以保证较小的dp值是上一个组的dp值。
			for ( k = 1 ; k <= cnt[v] ; k ++ )
				if ( j >= k ) dp[u][j] = max ( dp[u][j] , dp[u][j-k] + dp[v][k] ) ;
	}
	cnt[u] ++ ;
	for ( i = cnt[u] ; i >= 1 ; i -- ) dp[u][i] = dp[u][i-1] + r[u] ;
}

int main ()
{
	int n , m , i , a , b ;
	while ( scanf ( "%d%d" , &n , &m ) != EOF )
	{
		if ( n == 0 && m == 0 ) break ;
		init ( n ) ;
		for ( i = 1 ; i <= n ; i ++ )
		{
			scanf ( "%d%d" , &a , &b ) ;
			new_edge ( a , i ) ;
			r[i] = b ;
		}
		dfs ( 0 ) ;
		printf ( "%d\n" , dp[0][m+1] ) ;//0节点是不用计算体积的
	}
}


你可能感兴趣的:(树形DP)