“今日头条杯”首届湖北省大学程序设计竞赛 - D. Who killed Cock Robin (树形DP/乘法原理)

“今日头条杯”首届湖北省大学程序设计竞赛 - 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;
}

猜你喜欢

转载自blog.csdn.net/qq_41428565/article/details/80084518