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节点是不用计算体积的
}
}