树上独立集数量 树型DP

题目描述:

对于一棵树,独立集是指两两互不相邻的节点构成的集合。例如,图1有5个不同的独立集(1个双点集合、3个单点集合、1个空集),图2有14个不同的独立集,图3有5536个不同的独立集。 
这里写图片描述这里写图片描述这里写图片描述

输入:

第一行一个正整数n,表示点的数量。n最大为100000。 
接下来n-1行,有两个整数a、b,表示编号为a、b的两个点之间有一条边,其中a、b大于等于1,小于等于n。 
17 
1 2 
1 3 
2 4 
2 5 
3 6 
3 7 
5 8 
5 9 
7 10 
7 11 
8 12 
8 13 
10 14 
10 15 
12 16 
15 17

输出:

输出一行,包含一个整数,表示独立集的数量。由于这个数很大,你只需要输出这个数除以10081的余数。

分析:

这是一道树形DP。设f[i][0]表示在选i个节点的独集数,f[i][1]表示不选第i个节点的独集数。 
很明显,每一个节点的f都是有它的子节点得到的。 
如果选了第i个节点,那么它的子节点全部不选。所以,f[i][0]就等于它的子节点f[j][1]的乘积。 
反之,不选第i个节点,那么它的子节点可以选也可以不选,f[i][1]等于它的子节点(f[j][0] +f[j][1])的乘积。 
边就用奇怪的方法维护就行了(不要告诉我你不会前向新或边集数组)。

#include<cstdio>
#include<cstring>
#include<algorithm>
const int mo=10081;
int n,a[300001][2],g[300001],f[300001][2];
bool bz[300001];
void qsort1(int l, int r)  
{  
    int i=l;  
    int j=r;  
    int x;
    int t;
    x=a[(l+r)/2][0];
    while (i<=j)  
    {  
        while(a[i][0]<x) i++;  

        while(a[j][0]>x) j--;  
        if(i<=j)
        {   
            t=a[j][0];
            a[j][0]=a[i][0];  
            a[i][0]=t;
            t=a[j][1];
            a[j][1]=a[i][1];  
            a[i][1]=t;
            j--;
            i++;
        }  
    }    
    if (l<j) qsort1(l,j);  
    if (r>i) qsort1(i,r);  
}
void dfs(int x)
{
    int z1,z2,z=g[x],l=0;
    while (a[z][0]==x)
    {
        if (bz[a[z][1]]==false)
        {
            l=1;
            bz[a[z][1]]=true;
            dfs(a[z][1]);
            f[x][0]=(f[x][0]*f[a[z][1]][1])%mo;
            if (z==g[x]) 
            {
                z1=f[a[z][1]][0];
                z2=f[a[z][1]][1];
            }
            else
            {
                z1=(z1*f[a[z][1]][0]+z1*f[a[z][1]][1])%mo;
                z2=(z2*f[a[z][1]][0]+z2*f[a[z][1]][1])%mo;
            }
        }
        z++;
    }
    if (l==1) 
    {
        f[x][1]=(z1+z2)%mo;
    }
}
int main()
{
    int i,j,k;
    scanf("%d",&n);
    int zl=0;
    for (i=1;i<=n-1;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        zl++;
        a[zl][0]=x;
        a[zl][1]=y;
        zl++;
        a[zl][0]=y;
        a[zl][1]=x;
    }
    for (i=1;i<=n;i++)
    {
        f[i][1]=1;
        f[i][0]=1;
    }
    qsort1(1,zl);
    int z=1;
    for (i=1;i<=zl;i++)
    {
        if (a[z][0]!=a[i][0])
        {
            g[a[z][0]]=z;
            z=i;
        }
    }
    g[a[z][0]]=z;
    bz[1]=true;
    dfs(1);
    printf("%d",(f[1][0]+f[1][1])%mo);
}

 

posted @ 2017-09-19 22:30  Aragaki  阅读(940)  评论(0编辑  收藏  举报