“今日头条杯”首届湖北省大学程序设计竞赛(网络同步赛)D. Who killed Cock Robin 树形dp

版权声明:点个关注(^-^)V https://blog.csdn.net/weixin_41793113/article/details/89435183

链接:https://ac.nowcoder.com/acm/contest/104/C
来源:牛客网
 

题目描述

由于系统限制,C题无法在此评测,此题为现场赛的D题

Who killed Cock Robin?

I, said the Sparrow, With my bow and arrow,I killed Cock Robin.

Who saw him die?

I, said the Fly.With my little eye,I saw him die.

Who caught his blood?

I, said the Fish,With my little dish,I caught his blood.

Who'll make his shroud?

I, said the Beetle,With my thread and needle,I'll make the shroud.    

.........

All the birds of the air

Fell a-sighing and a-sobbing.

When they heard the bell toll.

For poor Cock Robin.

March 26, 2018

Sparrows are a kind of gregarious animals,sometimes the relationship between them can be represented by a tree.

The Sparrow is for trial, at next bird assizes,we should select a connected subgraph from the whole tree of sparrows as trial objects.

Because the relationship between sparrows is too complex, so we want to leave this problem to you. And your task is to calculate how many different ways can we select a connected subgraph from the whole tree.

输入描述:

 

The first line has a number n to indicate the number of sparrows. n≤2×105n≤2×105

The next n-1 row has two numbers x and y per row, which means there is an undirected edge between x and y.

输出描述:

 

The output is only one integer, the answer module 10000007 (107+7) in a line

示例1

输入

复制

4
1 2
2 3
3 4

输出

复制

10

说明

For a chain, there are ten different connected subgraphs: (1),(2),(3),(4),(1−2),(2−3),(3−4),(1−2−3),(2−3−4),(1−2−3−4)

题意:给出一颗树,求它的所有子树的总数。

思路:定义一个dp[],dp[u]是指以u为结点的子树的个数。

         可以推出:对于u所有的直接子节点v,dp[u]=dp[u]*(dp[v]+1);

         可以理解为(dp[v]+1)是在v结点形成的所有子树中加入一个u结点这样形成的一定含有u结点的子树总数。
--------------------- 
解析:维护一个数组size[i]表示以i为根节点且含有i的联通子图个数,然后从树的下层向上传递并进行计数,我们可以知道以当前节点的子节点为根节点且含有当前节点的子节点的联通子图个数,然后逐个遍历子节点并定义一个变量temp表示遍历过前面的子节点过后可以凑成的联通子图数,那么当遍历到新的一个子节点时,在以当前节点为根且使用当前遍历过所有子节点可以得到的新联通子图数为temp*size[v],总联通子图数为temp*size[v]+temp(v表示当前遍历的子节点),就这样逐个累计即可获得答案。
--------------------- 

题意:  给出一个有n个节点n-1条边的树,问你这颗数的所有子图的种类数目。例如下图:

一共有6种,分别是:(1)(2)(3)(1-2)(1-3)(1-2-3)

题解:     这里先定义每个节点的权值为以该节点为根的子图的种类的数目。那么对于所有叶子节点权值都为1(上图的2,3节点),而对于节点1,需要遍历他的每一个子树,并且子树间的权值需要相乘才得到节点1的权值。请看下图就可以发现它们之间的联系了。

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
const ll mod = 1e7+7;
const int MAX =200005;

vector<int> edge[MAX];
ll dp[MAX];

void dfs(int u,int pre){
    dp[u]=1;
    for(int i=0;i<edge[u].size();i++){
        int v = edge[u][i];
        if(v==pre)
            continue;
        dfs(v,u);
        dp[u] = dp[u]*(dp[v]+1)%mod;
    }
}


int main(){
    int n,x,y;
    scanf("%d",&n);

    for(int i=1;i<n;i++){
        scanf("%d%d",&x,&y);
        edge[x].push_back(y);
        edge[y].push_back(x);
    }

    dfs(1,-1);
    ll ans=0;
    for(int i=1;i<=n;i++)
        ans = (ans+dp[i])%mod;
    printf("%lld\n",ans);

	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_41793113/article/details/89435183