树形dp1——求树的最大独立集。

树的最大独立集定义为:在无根树上找出最多的不相连的点。

那么,怎么求最大独立集呢,用递归的思想构造动态规划。

设dp(i)表示以i为根的树所拥有的最大独立集。

那么我们思考转移,把问题变小发现,膜法转移,为什么呢,因为我们知道子问题,他的子树所拥有的最大独立集,却不能表示原问题的最大独立集。

因为这不能单纯相加,所以我们思考,还有什么可以影响决策,我们发现,可以影响决策的还有一个东西,那就是是否在独立集内部。

所以,dp(i,0)表示以i为根节点,并且i不在集合内部的最大独立集,如果i不在集合内部,那么他的子节点一定在或不在集合内部。

所以dp(i,0)=∑max(dp(i的子节点,1),dp(i的子节点,0));

dp(i,1)表示以i为根节点,并且i在集合内部的最大独立集,那么,以i为根的子节点一定不在集合内部。

所以dp(i,1)=∑dp(i的子节点,0)。

所以dp(i,1/0)=max(∑max(dp(i的子节点,1),dp(i的子节点,0)),∑dp(i的子节点,0));

附上代码

int dp(int u,int fa)
{
    f[u][0]=1;
    f[u][1]=0;
    for(int i=head[u];i;i=e[i].next)
    {
        int v=e[i].to;
        if(v==fa)continue;
        dp(v,u);
        f[u][0]+=f[v][1];
        f[u][1]+=max(f[v][0],f[v][1]);
    }
    return max(f[u][0],f[u][1]);
}

现在,来看一道题目

LazyChild OJ(blackoj.pas/c/cpp)
LazyChild 开了一家“善良 OJ”。但大多数人都不知道,这其实是家黑 OJ。亲爱的同学,请
不要惊讶,古时候有黑店,现代为什么不能有黑 OJ 呢?每 AC 一道题,网站便会自动在电
脑上安装一种木马。LazyChild 通过窃取信息获取收益(如网游帐号、OI 资料、YuanY
TT 的照片等等)。
作为一名资深黑客,老 Z 某日突然发现,“善良 OJ”上的木马,自己电脑上都没有。这可十
分让他过意不去。老 Z 决定通过多 A 题,来丰富自己电脑的病毒库。
经过调查,老 Z 发现,很多木马是不能共存的。比如“和谐”木马与“团结”木马,两者
只能任选其一。然而,老 Z 是个完美主义者,他想要自己的病毒库尽可能充实。
Z 不懈的追求最终感动了上天。天上的神仙(半仙?)“牛人雨”给这个问题稍稍降低了
一点难度。神仙规定,对于 n 种木马,有且仅有(n-1)对不能共存,并且对于每种木马,都存
在至少一个木马与之不能共存。
Z 不在乎自己 AC 多少题。请告诉他,他最多能从“善良 OJ”上获取木马的个数。
【输入】
第一行,一个正整数 n,表示木马个数。
剩余(n-1)行,每行一对木马,表示他们不能共存。(保证相同的木马可以共存,任意不同两
行的描述不等价)
木马编号从 0 (n-1)
【输入】
一行,老 Z 最多获得木马的个数。你可以认为开始时没有任何木马。
【输入样例】
3
0 1
1 2
【输出样例】
2
【数据规模】
对于 100%的数据,1<=n<=200 很明显的裸题。(*^▽^*)。

附上代码

#include<cstdio>
#include<algorithm>
#define N 200+10
using namespace std;
int f[N<<1][2],head[N<<1],num=1;
struct Edge{
    int next,to;
}e[N<<1];
void add(int from,int to)
{
    e[++num]=(Edge){head[from],to};
    head[from]=num;
}
void insert(int from,int to)
{
    add(from,to);
    add(to,from);
}
int dp(int u,int fa)
{
    f[u][0]=1;
    f[u][1]=0;
    for(int i=head[u];i;i=e[i].next)
    {
        int v=e[i].to;
        if(v==fa)continue;
        dp(v,u);
        f[u][0]+=f[v][1];
        f[u][1]+=max(f[v][0],f[v][1]);
    }
    return max(f[u][0],f[u][1]);
}
int main()
{
    freopen("blackoj.in","r",stdin);
    freopen("blackoj.out","w",stdout);
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n-1;i++)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        insert(u,v);
    }
    printf("%d\n",dp(0,0));
    fclose(stdout);
    return 0;
}

 

posted @ 2017-10-17 19:38  star_eternal  阅读(473)  评论(0编辑  收藏  举报