BZOJ 4753 二分+树形DP

Posted SiriusRen

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ 4753 二分+树形DP相关的知识,希望对你有一定的参考价值。

思路:

先二分答案

f[x][j]表示在x的子树里选j个点

f[x][j+k]=max(f[x][j+k],f[x][j]+f[v[i]][k]);

初始化

x!=0 -> f[x][1]=p[x]-s[x]*mid

x=0 -> f[x][0]=0

 类似4033的那样转移 看似O(n^3)实际O(n^2)

加一个二分 复杂度O(能过)

//By SiriusRen
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=2505;
int n,K,s[N],p[N],r[N],first[N],next[N],v[N],tot,size[N];
double f[N][N],mid;
void add(int x,int y){v[tot]=y,next[tot]=first[x],first[x]=tot++;}
void dfs(int x){
    if(x){size[x]=1;f[x][1]=p[x]-s[x]*mid;}
    else size[0]=0,f[0][0]=0;
    for(int i=first[x];~i;i=next[i]){
        dfs(v[i]);
        for(int j=size[x];j>=0;j--){
            for(int k=size[v[i]];k>=0;k--){
                f[x][j+k]=max(f[x][j+k],f[x][j]+f[v[i]][k]);
            }
        }
        size[x]+=size[v[i]];
    }
}
int main(){
    memset(first,-1,sizeof(first));
    scanf("%d%d",&K,&n);
    for(int i=1;i<=n;i++){
        scanf("%d%d%d",&s[i],&p[i],&r[i]);
        add(r[i],i);
    }
    double l=0,r=0x3f3f3f;
    while(r-l>1e-5){
        for(int i=0;i<=n;i++)
            for(int j=0;j<=n;j++)
                f[i][j]=-0x3f3f3f;
        mid=(l+r)/2;
        dfs(0);
        if(f[0][K]>0)l=mid;
        else r=mid;
    }
    printf("%.3lf\n",l);
}

 

以上是关于BZOJ 4753 二分+树形DP的主要内容,如果未能解决你的问题,请参考以下文章

bzoj4753: [Jsoi2016]最佳团体(分数规划+树形依赖背包)

BZOJ.4753.[JSOI2016]最佳团体(01分数规划 树形背包DP)

bzoj4753[Jsoi2016]最佳团体 分数规划+树形背包dp

[知识点]从BZOJ4753看01分数规划

[bzoj3420]Poi2013 Triumphal arch_树形dp_二分

[bzoj2097][Usaco2010 Dec]Exercise 奶牛健美操_贪心_树形dp_二分