[2017纪中10-26]摘Galo 树型背包

来源:互联网 发布:leslie矩阵是什么 编辑:程序博客网 时间:2024/06/05 21:01

题面
裸的树型背包。f[i][j]表示i的子树中选了j个的最优值。
O(n*k^2)+常数优化代码:

#include<iostream>#include<cstdio>#define chkmax(a,b) a=max(a,b)#define ll long longusing namespace std;const int maxn=100010;int n,k,w[maxn],sz[maxn];ll f[10010][1010];struct edge{    int t;    edge *next;}*con[maxn];void ins(int x,int y){    edge *p=new edge;    p->t=y;    p->next=con[x];    con[x]=p;}void dp(int v){    for(int i=k+1;i>0;i--)        f[v][i]=-1e18;    for(edge *p=con[v];p;p=p->next)    {        dp(p->t);        sz[v]+=sz[p->t];        for(int i=min(sz[v],k+1);i>=0;i--)            for(int j=0;j<=min(i,sz[p->t]);j++)                chkmax(f[v][i],f[v][i-j]+f[p->t][j]);    }    if(con[v]==NULL) sz[v]=1;    chkmax(f[v][1],(ll)w[v]);}int main(){    scanf("%d%d",&n,&k);    for(int i=2;i<=n;i++)    {        int fa;        scanf("%d%d",&fa,&w[i]);        ins(fa,i);    }    dp(1);    ll ans=0;    for(int i=0;i<=k+1;i++)        chkmax(ans,f[1][i]);    printf("%lld",ans);     return 0;}

O(n*k)DFS序做法:

#include<iostream>#include<cstdio>#define chkmax(a,b) a=max(a,b)#define ll long longusing namespace std;const int maxn=100010;int n,k,w[maxn],sz[maxn],tim,dfn[maxn];ll f[10010][1010];struct edge{    int t;    edge *next;}*con[maxn];void ins(int x,int y){    edge *p=new edge;    p->t=y;    p->next=con[x];    con[x]=p;}void dfs(int v){    dfn[++tim]=v;    sz[v]=1;    for(edge *p=con[v];p;p=p->next)    {        dfs(p->t);        sz[v]+=sz[p->t];    }}int main(){    scanf("%d%d",&n,&k);k++;    for(int i=2;i<=n;i++)    {        int fa;        scanf("%d%d",&fa,&w[i]);        ins(fa,i);    }    dfs(1);    for(int i=n;i>=1;i--)        for(int j=1;j<=k;j++)               f[dfn[i]][j]=max(f[dfn[i+sz[dfn[i]]]][j-1]+w[dfn[i]],f[dfn[i+1]][j]);    ll ans=0;    for(int i=0;i<=k;i++)        chkmax(ans,f[dfn[1]][i]);    printf("%lld",ans);     return 0;}
原创粉丝点击