题意:求无向树有多少个不同的子树。单点也算。
这道题比赛的时候公式对了,但是最后求和求错了,迷,也是思路没有完全理清楚。
树形dp,核心思想是合并子树。
由于无向,我们随意确定一个点为根,便确定了树的结构。
dp[i]表示以节点i为根的,包含节点i的子树总数。
用dfs从根往下搜,回溯的时候合并子树统计方法总数。
显然叶子结点v,dp[v]=1;
然后回溯到其父节点u时,我们把dp[v]与dp[u]合并。
然后方程就有了: dp[u]=dp[u]+dp[u]*dp[v];
表示新的以u为根的子树的方法总数=原来以u为根的子树的方法总数+原来以u为根的子树的方法总数加上边(u,v)后增加的方法总数。(自己画一下图不难验证)
最后加起来就可以了。不要忘了mod。。。
代码:
#include <bits/stdc++.h> #define ll long long using namespace std; const int mo=1e7+7; const int maxn=200010; int a[maxn],c[maxn],us[maxn]; ll dp[maxn],flag; ll tmp,ans,cnt; int n,m,x,y,z; char s[maxn]; vector<int>vc[maxn]; void add(int x,int y) { vc[x].push_back(y); } void dfs(int x,int fa) { dp[x]=1; for(int i=0;i<vc[x].size();i++) { int v=vc[x][i]; if(v!=fa){ dfs(v,x); dp[x]=(dp[x]+dp[x]*dp[v])%mo; } } return ; } int main(){ int T,cas; while(cin>>n) { int m=n-1; memset(dp,0,sizeof(dp)); for(int i=1;i<=n;i++) vc[i].clear(); while(m--){ cin>>x>>y; add(x,y); add(y,x); } ans=0; dfs(1,-1); for(int i=1;i<=n;i++) ans+=dp[i]; cout<<ans%mo<<endl; //if(flag) puts("Yes");else puts("No"); } return 0; }