HDU 1561 The more, The Better(樹形DP+01揹包)
阿新 • • 發佈:2018-12-21
題目連結
題意(這好像是中文題,不會別的語言=_=||)
思路
我們以0為根節點向外建樹,以前置點為起點,該點為終點,該點價值為線的權值。
由於每個結點只有一個父節點,每點權值等價兩點之間線上的權值。
第一組樣例可以這樣建圖
dp[i][j] 表示 i結點選j個的最大權值。
由於可以在任意子節點選部分數列然後組合而成,比如一個複雜的樹,某點選擇四個,可以由許多不同子節點選擇方式組合而成。這裡可以使用01揹包優化。
每次先dfs子節點出它的答案。回溯時01揹包一次,對於所有父節點dp[u][j],遍歷該兒子所有可能對其進行更新,dp[u][j] = max(dp[u][j], dp[u][k]+dp[v][j-k])
程式碼
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
int first[205], tot;
struct Edge
{
int v, nxt, w;
}e[205];
void add(int u, int v, int w)
{
e[tot].w = w;
e[tot].v = v;
e[tot].nxt = first[u];
first[u] = tot++;
}
int dp[205][205 ], n, m;
void dfs(int u)
{
dp[u][0] = 0;
for(int i = first[u]; ~i; i = e[i].nxt)
{
int v = e[i].v;
dp[v][1] = e[i].w;
dfs(v);
for(int j = m; j > 0; --j)
{
for(int k = j; k > min(u-1,0); --k) // 因為根節點是可以不選,dp[0][0]合法,其餘最少選1dp[][1]
{
// printf("**%d %d %d - %d %d %d **\n",u,k,dp[u][k], v,j-k,dp[v][j-k]);
dp[u][j] = max(dp[u][j], dp[u][k]+dp[v][j-k]);
}
// printf("---- %d %d %d\n",u,j,dp[u][j]);
}
}
}
int main()
{
int a, b;
while(scanf("%d%d",&n,&m), n)
{
tot = 0;
memset(first,-1,sizeof(first));
memset(dp,~0x3f,sizeof(dp));
for(int i = 1; i <= n; ++i)
{
scanf("%d%d",&a,&b);
add(a,i,b);
}
dfs(0);
printf("%d\n",dp[0][m]);
}
return 0;
}