汕头市队赛 SRM05 B(树形DP)

SRM 05 - YYL 杯 R1

背景&&描述

      有一个拥有n个城市的国家。这个国家由n-1条边连接起来。有一天国家发生叛乱。叛军已占领了一些城市。如果叛军占领的城市中,存在两个城市之间有边直接相连,则称这种情况是坏的。现在并不知道叛军占领了那些城市,问有多少种情况是坏的?

输入格式

第1行一个正整数n,表示国家的大小

第2行到第n行,每行两个数字x, y,表示x,y之间有一条边。

输出格式

一个整数表示方案数,答案对(1e9+7)取模

样例输入
2

1 2
样例输出
1
数据范围与约定
  • 对于0%的数据,和样例一毛一样。
  • 对于前20%的数据,1\leq n \leq 15
  • 对于接下来10%的数据,保证给出的是一条链,且 1 <= n <= 1e5
  • 对于接下来20%的数据,保证只有一个点的度数=3,其他点度数\leq2,且 1 <= n <= 1e5
  • 对于接下来20%的数据,保证给出的是一棵满二叉树,且 1 <= n <= 1e5
  • 对于剩下的数据,1 <= n <= 1e5,1\leq x,y\leq n ,x\neq y
样例解释

只有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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值