洛谷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;
}

posted @ 2021-07-16 20:10  inss!w!  阅读(35)  评论(0编辑  收藏  举报