#10153. 「一本通 5.2 例 1」二叉苹果树

2019-01-30 15:06:32


10153. 「一本通 5.2 例 1」二叉苹果树

题意

有一棵二叉苹果树,如果数字有分叉,一定是分两叉,即没有只有一个儿子的节点。这棵树共 $N$ 个节点,标号 $1$ 至 $N$ ,树根编号一定为 $1$ 。

我们用一根树枝两端连接的节点编号描述一根树枝的位置。一棵有四根树枝的苹果树,因为树枝太多了,需要剪枝。但是一些树枝上长有苹果,给定需要保留的树枝数量,求最多能留住多少苹果。 tree.png

思路

设 $f[i][j]$ 表示以i为根节点,保留j个节点的最大苹果数量

$$f[i][j]=max{f[l[i]][k]+f[r[i]][j-k-1]+a[i]}(0<=k<=j-1)$$

$$f[i][j]=0(0<i<=n,0<=j<=Q+1)$$

$$f[i][j]=a[i](j!=0,l[i]==0,r[i]==0)$$

$$Answer:f[1][Q+1]$$

#include<bits/stdc++.h>
#define ll long long
using namespace std;
inline ll read(){
    char ch=getchar();ll res=0,f=1;
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') res=res*10+ch-'0',ch=getchar();
    return res*f;
}
inline void write(ll x){
    if(x<0) putchar('-'),x=-x;
    if(x<10) putchar(x+'0');
    else{
        write(x/10);
        putchar(x%10+'0');
    }
}
ll n,Q,f[110][110],a[110],l[110],r[110],mp[110][110];
void MakeTree(int x){
    for(int i=1;i<=n;i++){
        if(mp[x][i]!=-1){
            l[x]=i;a[i]=mp[x][i];
            mp[x][i]=mp[i][x]=-1;
            MakeTree(i);
            break; 
        }
    }//Make Left Son
    for(int i=1;i<=n;i++){
        if(mp[x][i]!=-1){
            r[x]=i;a[i]=mp[x][i];
            mp[x][i]=mp[i][x]=-1;
            MakeTree(i);
            break;
        }
    }//Make Right Son
}
int DP(int x,int j){

    if(j==0){f[x][j]=0;return 0;}
    if((!l[x])&&(!r[x])){f[x][j]=a[x];return a[x];}
    if(f[x][j]>0) return f[x][j];
    for(int k=0;k<j;k++) f[x][j]=max(f[x][j],DP(l[x],k)+DP(r[x],j-k-1)+a[x]);
    return f[x][j];
}
int main(){
    n=read();Q=read();Q++;
    memset(mp,-1,sizeof(mp));
    for(int i=1;i<=n-1;i++){
        int x=read(),y=read(),z=read();
        mp[y][x]=mp[x][y]=z;
    }
    MakeTree(1);
    write(DP(1,Q));putchar('\n');
    /*
    cout<<"-----------------------------------"<<endl;
    for(int i=1;i<=n;i++){
        cout<<"Node "<<i<<":\n";
        cout<<"Left Son:"<<l[i]<<" Right Son:"<<r[i]<<endl;
        cout<<"Val:"<<a[i]<<endl;
        cout<<"DP :\n";
        for(int j=0;j<=Q;j++){
            cout<<"Has "<<j<<":"<<f[i][j]<<endl;
        }
        cout<<endl;
    } 
    */
    return 0;
}
//设f[i][j]表示以i为根节点,保留j个节点的最大苹果数量
//f[i][j]=max{f[l[i]][k]+f[r[i]][j-k-1]+a[i]}(0<=k<=j-1) 
//f[i][j]=0(0<i<=n,0<=j<=Q+1)
//f[i][j]=a[i](j!=0&&l[i]==0&&r[i]==0)
//Answer:f[1][Q+1]
/*
Sample Input:
5 2
1 3 1
1 4 10
2 3 20
3 5 20
Sample Output:
21
*/