Luogu P2015二叉苹果树

Description:

有一棵苹果树,如果树枝有分叉,一定是分2叉(就是说没有只有1个儿子的结点)。这棵树共有N个结点(叶子点或者树枝分叉点),编号为1-N,树根编号一定是1。我们用一根树枝两端连接的结点的编号来描述一根树枝的位置。现在这颗树枝条太多了,需要剪枝。但是一些树枝上长有苹果。给定需要保留的树枝数量,求出最多能留住多少苹果。

Analysis:

保留Q个树枝即保留 Q + 1个节点。对于一个节点所在的树,保留j个节点,它自己必须保留,子树分三种情况:①左子树为空,右子树保留j-1个节点。②右子树为空,左子树保留j-1个节点。③左右子树均不为空,左子树保留k个节点,则右子树保留j - k - 1个节点(0 <= k <= j - 1)
dp[i][j] := 以i为根的树中保留j个节点的最大权值和。状态转移方程:dp[i][j] = max{dp[lc[i][k] + dp[rc[i][j-k-1] + a[i]},初始化dp[i][j] = 0,ans = dp[1][Q+1]

Code

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<queue>
#define N 110
using namespace std;
struct edge{
	int to,w,next;
}e[N];
int dp[N][N],lc[N],rc[N],a[N],map[N][N],n,q;
inline void add(int u,int v,int w){
	
}
void build(int k){
//    >= 0   !!!!
    for(int i = 1;i <= n;++i){
        if(map[k][i] >= 0){
            lc[k] = i;
            a[i] = map[k][i];//?
            map[i][k] = map[k][i] = -1;
            build(i);
            break;
        }
    }
    for(int i = 1;i <= n;++i){
    // >= 0    !!!!
        if(map[k][i] >= 0){
            rc[k] = i;
            a[i] = map[k][i];
            map[i][k] = map[k][i] = -1;
            build(i);
            break;
        }
    }
}
int DP(int i,int j){
    if(j == 0) return 0;
    else if(dp[i][j] > 0) return dp[i][j];
    else if((lc[i] == 0) && (rc[i] == 0)) return a[i];
    else if(lc[i] == 0) return dp[i][j] = DP(rc[i],j - 1) + a[i];
    else if(rc[i] == 0) return dp[i][j] = DP(lc[i],j - 1) + a[i];
    else{
        for(int k = 0;k <= j - 1;++k){
            dp[i][j] = max(dp[i][j],DP(lc[i],k) + DP(rc[i],j - 1 - k) + a[i]);
        }
        return dp[i][j];
    }
}
void solve(){
    build(1);
    int ans = DP(1,q);
    printf("%d\n",ans);
}
int main(){
    scanf("%d%d",&n,&q);
    ++q;
    memset(map,-1,sizeof(map));
    for(int i = 1;i < n;++i){
        int x,y,z;
        scanf("%d%d%d",&x,&y,&z);
        map[x][y] = map[y][x] = z;
    }
    solve();
    return 0;
}
posted @ 2019-04-08 21:25  Zforw  阅读(45)  评论(0编辑  收藏  举报