B SRM 05 - YYL 杯 R1
背景&&描述
有一个拥有n个城市的国家。这个国家由n-1条边连接起来。有一天国家发生叛乱。叛军已占领了一些城市。如果叛军占领的城市中,存在两个城市之间有边直接相连,则称这种情况是坏的。现在并不知道叛军占领了那些城市,问有多少种情况是坏的?
输入格式
第1行一个正整数n,表示国家的大小
第2行到第n行,每行两个数字x, y,表示x,y之间有一条边。
输出格式
一个整数表示方案数,答案对(1e9+7)取模
样例输入
2 1 2
样例输出
1
数据范围与约定
- 对于0%的数据,和样例一毛一样。
- 对于前20%的数据,
- 对于接下来10%的数据,保证给出的是一条链,且 1 <= n <= 1e5
- 对于接下来20%的数据,保证只有一个点的度数,其他点度数,且 1 <= n <= 1e5
- 对于接下来20%的数据,保证给出的是一棵满二叉树,且 1 <= n <= 1e5
- 对于剩下的数据,1 <= n <= 1e5,
样例解释
只有1和2同时叛变时才满足题意。
以下题解搬运自出题人yyl:“直接做dp应该也是可以的。但是补集转化之后,我们发现其实就是问从点集V中选出若干个点构成点集S,满足S是一个独立集(即S中任意两点没有边直接相连)。设方案数为x。答案就是2^n -x。”
而独立集的方案数我们可以通过树形dp求出
f[i][0/1]表示以i为根节点,i点选或不选的方案数
转移方程看代码啦
其实理解的还不是很透彻
以后再加强辣
注意乘法爆int!!!
#include<cstdio>
#include<cstring>
const int mod=1e9+7,N=1e5+110;
struct node
{
int to,next;
}e[N*2];
int first[N];
long long int dp[N][2];
int cnt=0;
void insert(int u,int v)
{
e[++cnt]=(node){v,first[u]};first[u]=cnt;
e[++cnt]=(node){u,first[v]};first[v]=cnt;
}
void dfs(int x,int fa)
{
dp[x][0]=dp[x][1]=1;
for(int k=first[x];k;k=e[k].next)
{
if(e[k].to==fa) continue;
dfs(e[k].to,x);
dp[x][0]=(dp[e[k].to][0]+dp[e[k].to][1])%mod*dp[x][0]%mod;
dp[x][1]=dp[x][1]*dp[e[k].to][0]%mod;
}
}
int main()
{
int n;
scanf("%d",&n);
int x,y;
for(int i=1;i<n;i++)
{
scanf("%d %d",&x,&y);
insert(x,y);
}
dfs(1,0);
long long int ans=1;
for(int i=1;i<=n;i++) ans=(ans<<1)%mod;
printf("%lld\n",((ans-dp[1][0]-dp[1][1]+mod)%mod+mod)%mod);
return 0;
}