zoukankan      html  css  js  c++  java
  • 洛谷P2015—二叉苹果树(树形DP)

    题意

    有n个结点,树枝上有苹果,需要保留一些树枝,问最多能留下多少苹果?

    输入输出

    输入:第一行 2个整数 N 和 Q,分别表示表示树的结点数,和要保留的树枝数量。
    接下来 N-1 行,每行 3 个整数,描述一根树枝的信息:前 2 个数是它连接的结点的编号,第 3 个数是这根树枝上苹果的数量。
    输出:一个数,最多能留住的苹果的数量。

    思路

    状态转移数组
    dp[i][j]为以i为根节点的子树保留j条树枝时获得的最大的苹果数量
    最终的答案为dp[1][q]
    状态转移方程
    dp[u][j] = max(dp[u][j],dp[v][k] + dp[u][j-k-1] + edge[i]);
    在u结点保留的j根树枝中,分k根树枝给它的子树,即dp[v][k],再加上子树到u那条边上的苹果树,u还剩下j-k+1条边

    #include <iostream>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    
    const int MAX_N = 110; //最多结点数
    int tot;    //标记边的序号
    int head[MAX_N << 1],nxt[MAX_N << 1],ver[MAX_N << 1],edge[MAX_N << 1];  //建树要用到的数组
    int dp[MAX_N][MAX_N];
    int n,q;
    
    void addedge(int u,int v,int w){  //根据邻接表建树的过程
        ver[++tot] = v;     //tot条边指向的点为v
        nxt[tot] = head[u]; //nxt保存以u为始点的下一条边的序号
        head[u] = tot;      //head[u]保存以u为始点的边的序号
        edge[tot] = w;
    }
    
    void dfs(int u,int fa){
        dp[u][0] = 0;
        for(int i = head[u];i;i = nxt[i]){
            int v = ver[i];
            if(v == fa) continue;
            dfs(v,u);
            for(int j = q; j >= 1;j--){    //枚举当前可以选的树枝数
                for(int k = j - 1;k >= 0;k--){  //枚举子树可以选的树枝数
                    dp[u][j] = max(dp[u][j],dp[v][k] + dp[u][j-k-1] + edge[i]);
                }
            }
        }
    }
    int main(){
    	cin >> n >> q;
    	int u,v,w;
    	for(int i = 0;i < n - 1;i++){
            cin >> u >> v >> w;
            addedge(u,v,w);
            addedge(v,u,w);
    	}
    	dfs(1,-1);
    	cout << dp[1][q];
    	return 0;
    }
    
    
    作者:inss!w!
    版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
  • 相关阅读:
    拥塞避免
    计算机网络常考
    [CODEVS1014]装箱问题
    [CODEVS2055]集合划分
    [CODEVS3641]上帝选人
    [GRYZ2014]递增子序列最大和
    [GRYZ2014]最大连续子序列的和
    金矿模型看动归
    [CODEVS1220]数字三角形
    [CODEVS1294]全排列
  • 原文地址:https://www.cnblogs.com/Hfolsvh/p/15015586.html
Copyright © 2011-2022 走看看