洛谷2015 二叉苹果树 树形DP

https://www.luogu.org/problemnew/show/P2015

二叉苹果树

时间限制: 1 Sec  内存限制: 128 MB

题目描述

有一棵苹果树,如果树枝有分叉,一定是分 2 叉(就是说没有只有 1 个儿子的结点)

这棵树共有 N 个结点(叶子点或者树枝分叉点),编号为 1 - N 树根编号一定是 1。

我们用一根树枝两端连接的结点的编号来描述一根树枝的位置。下面是一棵有 4 个树枝的树

2   5
 \ / 
  3   4
   \ /
    1

现在这颗树枝条太多了,需要剪枝。但是一些树枝上长有苹果。

给定需要保留的树枝数量,求出最多能留住多少苹果。

输入

输入包含多组测试数据。

对于每一组测试样例:

第 1 行有 2 个数,N 和 Q(1 <= Q <= N,1 < N <= 100)。

N 表示树的结点数,Q 表示要保留的树枝数量。接下来 N-1 行描述树枝的信息。

每行 3 个整数,前两个是它连接的结点的编号。第 3 个数是这根树枝上苹果的数量。

每根树枝上的苹果不超过 30000 个。

输出

一个数,最多能留住的苹果的数量。

样例输入

5 2
1 3 1
1 4 10
2 3 20
3 5 20

样例输出

21

分析:

状态表示:dp[i][j]表示子树i,保留j个节点的最大权值
每条边的权值,可以看作是儿子的权值,那么就可以对所有的子树做分组背包,即每个子树可以选则1,2..j-1条边分配给它

#include<bits/stdc++.h>
using namespace std;
const int maxn=150;
int dp[maxn][maxn];
vector< pair<int,int> >adj[maxn];//存储无向图
#define inf 0x3f3f3f3f
int tot[maxn];//tot[i]表示与节点i直接相邻的节点个数
int dfs(int u,int fa)//u的父节点为fa
{
    tot[u]=1;
    for(int i=0;i<adj[u].size();i++)
    {
        int v=adj[u][i].first;
        if(v==fa)   continue;
        tot[u]+=dfs(v,u);
    }
    for(int i=0;i<adj[u].size();i++)
    {
        int v=adj[u][i].first;//与u直接相连节点
        int w=adj[u][i].second;//这条边的权值
        if(v==fa)   continue;
        for(int j=tot[u];j>1;j--)
        {
            for(int k=1;(k<j)&&(k<=tot[v]);k++)
            {
                dp[u][j]=max(dp[u][j],dp[u][j-k]+dp[v][k]+w);
            }
        }
    }
    return tot[u];
}
int main()
{
    int n,p;
    while(~scanf("%d%d",&n,&p)){
        for(int i=0;i<maxn;i++)
            adj[i].clear();
            int u,v,w;
        for(int i=1;i<n;i++)
        {
            scanf("%d%d%d",&u,&v,&w);
            adj[u].push_back(make_pair(v,w));
            adj[v].push_back(make_pair(u,w));
        }
        memset(dp,0,sizeof(dp));
        dfs(1,-1);//从任意一点开始搜索
        printf("%d\n",dp[1][p+1]);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_40507857/article/details/81268284