您的位置:首页 > 其它

独立集

2016-09-23 19:03 197 查看

题目描述:

对于一棵树,独立集是指两两互不相邻的节点构成的集合。例如,图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的余数。

5536

分析:

这是一道树形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])的乘积。

边就用奇怪的方法维护就行了(不要告诉我你不会前向新或边集数组)。

CODE:

#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);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: