1. 程式人生 > >HDU 1561 The more, The Better(樹形DP+01揹包)

HDU 1561 The more, The Better(樹形DP+01揹包)

題目連結
題意(這好像是中文題,不會別的語言=_=||)
思路

我們以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; }