“今日头条杯”首届湖北省大学程序设计竞赛 - D. Who killed Cock Robin (树形DP/乘法原理)
题目链接: D. Who killed Cock Robin
题意
给你一个树(n个点,n-1条边)让你找到其中的连通图组合数量,例如有个退化过的树 1->2->3->4,现在这里的连通图组合数量是 (1),(2),(3),(4),(1-2),(2-3),(3-4),(1-2-3),(2-3-4),(1-2-3-4) ,10个。
思路
这里先定义每个节点的权值为以该节点为根的子图的种类的数目。那么对于所有叶子节点权值都为1,而对于节点1,需要遍历他的每一个子树,并且子树间的权值需要相乘才得到节点1的权值。请看下图就可以发现它们之间的联系了。每一个now[i]存的都是包括i点在内,不包括父节点,最大数量的连通图。这里的DP其实也用到了乘法原理。
代码
#include <bits/stdc++.h>
using namespace std;
#define rep(i,j,k) for(int i = (int)(j);i <= (int)(k);i ++)
#define per(i,j,k) for(int i = (int)(j);i >= (int)(k);i --)
#define mmm(a,b) memset(a,b,sizeof(a))
#define pb push_back
typedef long long ll;
const int INF = (int)0x3f3f3f3f;
const int MAXN = (int)2e5+7;
const ll MOD = (ll)1e7+7;
ll now[MAXN];
ll ans;
vector<int> vp[MAXN];
ll dfs(int x){
now[x] = 1;
ll res = 1;
rep(i,0,vp[x].size()-1){
int t = vp[x][i];
if (now[t]) continue;
res = (res*(dfs(t)+1))%MOD;
}
now[x] = res;
return res;
}
int main()
{
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
int N;
cin >> N;
rep(i,1,N-1){
int x,y;
cin >> x >> y;
vp[x].pb(y);
vp[y].pb(x);
}
dfs(1);
rep(i,1,N){
ans = (ans+now[i])%MOD;
}
cout << ans << endl;
}