1. 程式人生 > 實用技巧 >P2015 二叉蘋果樹

P2015 二叉蘋果樹

蘋果二叉樹

有一棵二叉蘋果樹,如果樹枝有分叉,一定是分兩叉,即沒有隻有一個兒子的節點。

這棵樹共 \(N\) 個節點,編號為 \(1\)\(N\),樹根編號一定為 \(1\)

我們用一根樹枝兩端連線的節點編號描述一根樹枝的位置。

一棵蘋果樹的樹枝太多了,需要剪枝。但是一些樹枝上長有蘋果,給定需要保留的樹枝數量,求最多能留住多少蘋果。

這裡的保留是指最終與1號點連通。

輸入格式

第一行包含兩個整數 \(N\)\(Q\),分別表示樹的節點數以及要保留的樹枝數量。

接下來 \(N−1\) 行描述樹枝資訊,每行三個整數,前兩個是它連線的節點的編號,第三個數是這根樹枝上蘋果數量。

輸出格式

輸出僅一行,表示最多能留住的蘋果的數量。

資料範圍

\(1≤Q<N≤100\)
\(N≠1\)
每根樹枝上蘋果不超過 \(30000\) 個。

輸入樣例:

5 2
1 3 1
1 4 10
2 3 20
3 5 20

輸出樣例:

21

題解

樹形動態規劃沒得跑,

\(f[u][j]\)表示\(u\)這個節點選擇\(j\)條邊的最大價值

每一棵子樹看出一組揹包,若需要選擇子樹\(son\)的時候,則根結點u到子樹\(son\)的邊一定用上,因此能用上的總邊數一定減\(1\),總共可以選擇\(j\)條邊時,當前子樹\(son\)分配的最大邊數是\(k\),那麼\(u\)為根的子樹的分配數量是\(j-k-1\)

\(f[u][j]=max(f[u][j],f[u][j-k-1]+f[v][k]+e[i])\)

#include<bits/stdc++.h>
using namespace std;
const int N=3000;
int f[N][N];
int n,m;
int ne[N],ver[N],head[N],idx,e[N];
void add(int u,int v,int w)
{
    ne[idx]=head[u];
    ver[idx]=v;
    head[u]=idx;
    e[idx]=w;
    idx++;
}

void dp(int x,int father)
{
    for(int i=head[x];i!=-1;i=ne[i])
    {
        int y=ver[i];
        if(y==father)continue;
        dp(y,x);
        for(int j=m;j>=0;j--)
        {
            for(int k=0;k+1<=j;k++)
            {
                f[x][j]=max(f[x][j],f[x][j-k-1]+f[y][k]+e[i]);
            }
        }
    }
}

int main()
{
    memset(head,-1,sizeof(head));
    cin>>n>>m;
    for(int i=1;i<n;i++)
    {
        int a,b,c;
        cin>>a>>b>>c;
        add(a,b,c);
        add(b,a,c);
    }
    dp(1,0);
    cout<<f[1][m]<<endl;
    return 0;
}