树形DP——Luogu2014 选课

题面:传送门
首先显然的这个树形结构的东西是一个森林
我们随便搞一个超级汇点变成一棵树好了
然后问题来了,这棵树是多叉树……
我想的状态是这样的:f[i][j]表示在以i节点为根的子树内取j个(符合题意)的最大值
转移的时候把子树内的转移到这棵子树的根即可,只不过这个根必选
可惜的是如果按照多叉树来转移的话转移会很麻烦。。。
所以只能多叉转二叉了,也就是说左儿子右兄弟
然后就可以用上面转移的方法转移了
对于超级汇点来说,因为按照上面转移,超级汇点也必须选上(你也可以特判)
所以最后答案是f[超级汇点][m+1]

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<iostream>
#include<cstdlib>
#include<queue>
#include<climits>
#include<ctime>
#include<string>
using namespace std;
int n,m,ls[100001],rs[100001],v[100001],s[100001];
int nedge=0,p[100001],nex[100001],head[100001];
int f[310][310];
inline void addedge(int a,int b){
    p[++nedge]=b;nex[nedge]=head[a];head[a]=nedge;
}
inline void dfs(int x){//多叉转二叉
    int k=head[x];
    if(!k)return;
    ls[x]=p[k];dfs(p[k]);
    int pp=p[k];
    for(k=nex[k];k;k=nex[k]){
        rs[pp]=p[k];dfs(p[k]);
        pp=p[k];
    }
}
inline void dp(int x){//树形DP
    if(!x)return;
    dp(ls[x]),s[x]+=s[ls[x]];
    dp(rs[x]),s[x]+=s[rs[x]];
    s[x]++;
    for(int i=1;i<=s[x];i++){
        f[x][i]=i>s[rs[x]]?0:f[rs[x]][i];
        for(int j=0;j<=min(s[ls[x]],i-1);j++){
            if(i-j-1>s[rs[x]])continue;
            int l=f[ls[x]][j],r=f[rs[x]][i-j-1];
            f[x][i]=max(f[x][i],l+r+v[x]);
        }
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        int x;scanf("%d%d",&x,&v[i]);
        if(x==0)x=n+1;
        addedge(x,i);
    }
    dfs(n+1);dp(n+1);
    printf("%d",f[n+1][m+1]);
    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值