玩具 (toy.pas/c/cpp)
【题目描述】
一天小D去超市买回来了一个玩具,这个玩具是由n个球和一些支架组成, 每一个支架连接着两个不同的球,通过支架每两个球之间的简单路径有且 只有一条,如果某一个支架的两端的球全被拿走,那么这个玩具就会垮掉 。小D无聊的时候开始拿走球,问,他有多少中拿球方案,使玩具不垮。
【输入数据】
输入文件名为toy.in。 第一行一个数n 表示球的个数 接下来若干行每行两个数a,b表示有一个支架连接着球a和球b
【输出数据】
输出文件名为toy.out. 一行一个数ans 表示DRJ拿球的方案数mod 109+7(可以一个球也不拿)
【样例输入】
5
1 2
1 3
2 4
2 5
【样例输出】
14
【数据范围】
30%的数据满足n<=20;
50%的数据满足n<=1000
100%的数据满足 n<=500000;
思路分析
每条边至少要选1个点,则转化成一个比较裸的树形dp问题。
#include<bits/stdc++.h>
using namespace std;
const int mod=1e9+7;
int cnt,head[500010],n;
long long f[1000010][2];
inline long long read(){
long long x=0;char ch=getchar();
while(ch<'0'||ch>'9')ch=getchar();
while(ch>='0'&&ch<='9'){
x=(x<<3)+(x<<1)+ch-'0';
ch=getchar();
}
return x;
}
struct edge{
int u,v,nxt;
}e[1000010];//注意建双向边要开双倍空间
inline void add(int u,int v){
e[++cnt].u=u;
e[cnt].v=v;
e[cnt].nxt=head[u];
head[u]=cnt;
}
void dfs(int u,int fa){//上一条边
f[u][1]=1,f[u][0]=1;//初值
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].v;
if(v==fa)continue;
dfs(v,u);
f[u][1]*=f[v][1]+f[v][0];//若选此点,则另一个点选或不选
f[u][0]*=f[v][1];//若不选,则另一个点必须选
f[u][1]%=mod,f[u][0]%=mod;
}
}
int main(){
n=read();
int u,v;
for(int i=1;i<n;++i){
u=read(),v=read();
add(u,v),add(v,u);
}
dfs(1,0);
printf("%lld",(f[1][1]+f[1][0])%mod);//第一个点选或不选
return 0;
}