zoukankan      html  css  js  c++  java
  • 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
    ",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;
    }
    
    岂能尽如人意,但求无愧我心
  • 相关阅读:
    7-36 复数四则运算
    7-35 有理数均值
    7-34 通讯录的录入与显示
    7-33 有理数加法
    7-32 说反话-加强版
    POJ-2524-Ubiquitous Religions
    POJ-2406-Power Strings
    HDU-1072-Nightmares
    POJ-1961-Period(ZOJ-2177)
    POJ-1961-Period(ZOJ-2177)
  • 原文地址:https://www.cnblogs.com/Zforw/p/10673540.html
Copyright © 2011-2022 走看看