树形dp学习笔记

直接放例题吧:

codevs1380:没有上司的舞会

题意:
某公司要举办一次晚会,但是为了使得晚会的气氛更加活跃,每个参加晚会的人都不希望在晚会中见到他的直接上司,现在已知每个人的活跃指数和上司关系(当然不可能存在环),求邀请哪些人(多少人)来能使得晚会的总活跃指数最大。

思路:
任何一个点的取舍可以看作一种决策,那么状态就是在某个点取的时候或者不取的时候,以他为根的子树能有的最大活跃总值。分别可以用f[i,1]和f[i,0]表示第i个人来和不来。

当i来的时候,dp[i][1] += dp[j][0];//j为i的下属
当i不来的时候,dp[i][0] +=max(dp[j][1],dp[j][0]);//j为i的下属

#include
#include
#include
using namespace std;
const int N=6010;
int root,fa[N],n,f[N][2]={0};
bool use[N];
void dp(int x)
{
    int i,u;
    use[x]=false;
    for(i=1;i<=n;++i){
        if(use[i]&&fa[i]==x){
            dp(i);
            f[x][0]+=max(f[i][0],f[i][1]);
            f[x][1]+=f[i][0];
        }
    }
}
int main()
{
    int x,y,i,j;
    scanf("%d",&n);
    memset(use,1,sizeof(use));
    for(i=1;i<=n;++i)
      scanf("%d",&f[i][1]);
    for(i=1;i<=n;++i){
        scanf("%d%d",&x,&y);
        if(i==n) break;
        fa[x]=y;
    }
    for(i=1;i<=n;++i){
        if(!fa[i]){
            root=i;
            break;
        }
    }
    dp(root);
    printf("%d\n",max(f[root][0],f[root][1]));
}

cogs1186访问艺术馆

【问题描述】
经过数月的精心准备,Peer Brelstet,一个出了名的盗画者,准备开始他的下一个行动。艺术馆的结构,每条走廊要么分叉为两条走廊,要么通向一个展览室。Peer知道每个展室里藏画的数量,并且他精确测量了通过每条走廊的时间。由于经验老到,他拿下一幅画需要5秒的时间。你的任务是编一个程序,计算在警察赶来之前,他最多能偷到多少幅画。

【输入】
第1行是警察赶到的时间,以s为单位。第2行描述了艺术馆的结构,是一串非负整数,成对地出现:每一对的第一个数是走过一条走廊的时间,第2个数是它末端的藏画数量;如果第2个数是0,那么说明这条走廊分叉为两条另外的走廊。数据按照深度优先的次序给出,请看样例。
一个展室最多有20幅画。通过每个走廊的时间不超过20s。艺术馆最多有100个展室。警察赶到的时间在10min以内。
【输出】
输出偷到的画的数量。
【样例】
gallery.in gallery.out
60 2
7 0 8 0 3 1 14 2 10 0 12 4 6 2

题解:先用递归建树,保存一下父节点,儿子节点,到父亲的距离,自己末端的画数(有的变量可能用不到)。然后开始树状dp,f[i][j]表示第i个节点取j幅画,然后对左右子树进行选择。一点点的算出来。

#include
#include
#include
using namespace std;
const int N=500;
struct S{
    int l,r,fa,va,len;
}tr[N];
int s,n=0,f[N][N],num[N]={0};
void in(int i)
{
    int x,y,t;
    scanf("%d%d",&x,&y);
    n+=1;t=n;
    if(tr[i].l==0) tr[i].l=n;
    else tr[i].r=n;
    tr[n].fa=i;
    tr[n].len=x*2;
    if(y) tr[t].va=y;
    else{
        in(t);in(t);
    }
}
void dp(int x)
{
    int i,j;
    if(tr[x].l==0){
        num[x]=tr[x].va;
        for(i=1;i<=tr[x].va;++i)
          f[x][i]=5*i;
        return ;
    }
    dp(tr[x].l);
    if(x) dp(tr[x].r);
    f[x][0]=0;
    for(i=0;i<=num[tr[x].l];++i){
        for(j=0;j<=num[tr[x].r];++j){
            if(i==0) f[x][j]=min(f[x][j],f[tr[x].r][j]+tr[tr[x].r].len);
            else if(j==0) f[x][i]=min(f[x][i],f[tr[x].l][i]+tr[tr[x].l].len);
            else f[x][i+j]=min(f[x][i+j],f[tr[x].l][i]+tr[tr[x].l].len+f[tr[x].r][j]+tr[tr[x].r].len);
        }
    }
    num[x]=num[tr[x].l]+num[tr[x].r];
}
int main()
{
    freopen("gallery.in","r",stdin);
    freopen("gallery.out","w",stdout);
    int i,j,ans=0;
    scanf("%d",&s);
    memset(f,127/3,sizeof(f));
    in(0);
    dp(0);
    for(i=0;i<=num[0];++i)
      if(f[0][i]<s)
        ans=max(ans,i);
    printf("%d\n",ans);
}

你可能感兴趣的:(树形dp,动态规划)