樹形dp_1019考試 toy題解

玩具 (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;
} 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章