【51Nod1353】树

来源:互联网 发布:java研发工程师南昌 编辑:程序博客网 时间:2024/06/05 22:46

今天小a在纸上研究树的形态,众所周知的,有芭蕉树,樟树,函树,平衡树,树套树等等。那么小a今天在研究的就是其中的平衡树啦。
小a认为一棵平衡树的定义为一个n个点,从1到n编号,n-1条边,且任意两点间一定存在唯一一条简单路径,且n>=k。
现在小a看到一棵很大很大的树,足足有n个节点,这里n一定大于等于k!为了方便起见,它想把这个树删去某些边,使得剩下的若干个联通块都满足是平衡树。这时,小b走过来,不屑一顾的说,如果我一条边都不删,那么也算一棵平衡树咯。
小a对于小b的不屑感到很不爽,并问小b,你能算出我删边的方案总数使得满足我的条件吗?两个删边的方案A,B不同当且仅当存在某一条边属于集合A且不属于集合B,或者存在某一条边属于集合B且不属于集合A。为了让你方便,你只要告诉我答案对1000000007(1e9+7)取模就行了。
小b犯了难,找到了身为程序猿的你。
Hint:
样例解释,
第一种方案为不删边,
第二种方案为删去2 3这一条边,
第三种方案为删去3 4这一条边。

Input
第一行读入两个正整数n,k(1<=k<=n<=2000)。
接下来n-1行,每行两个正整数A,B ( 1<= A,B<= n),表示A与B有一条边相连,题目保证在不删任何一条边的情况下是一棵平衡树。
Output
一个整数,表示答案对1000000007(1e9+7)取模后的值。
Input示例
5 2
1 2
2 3
3 4
4 5
Output示例
3

题解
dp[u][i]表示u为根规模为i且其余树为平衡树的方案数,容易得到dp[u][i+j]+=dp[u][i]*dp[v][j];记dp[u][0]表示u为根合法的方案数,则每次转移前dp[u][i]=dp[u][i]*dp[v][0];

代码

#include<iostream>#include<cstdio>#include<cstring>#include<cstdlib>#include<set>#include<ctime>#include<vector>#include<cmath>#include<algorithm>#include<map>#define mod 1000000007 #define ll long long  using namespace std;inline int read(){    int x=0,f=1;char ch=getchar();    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}    return x*f;}int tot,n,k,dp[2005][2005],size[2005];int ret[4005],Next[4005],Head[4005];inline void ins(int u,int v){    ret[++tot]=v;Next[tot]=Head[u];Head[u]=tot;}void dfs(int u,int pre){    dp[u][1]=1;size[u]=1;    for (int i=Head[u];i;i=Next[i])    {        int v=ret[i];        if (v==pre) continue;        dfs(v,u);        for (int i=size[u];i>0;i--)        {            for (int j=1;j<=size[v];j++)                dp[u][i+j]=(dp[u][i+j]+(ll)dp[u][i]*dp[v][j]%mod)%mod;            dp[u][i]=(ll)dp[u][i]*dp[v][0]%mod;        }        size[u]+=size[v];    }    for (int i=k;i<=size[u];i++) dp[u][0]=(dp[u][0]+dp[u][i])%mod;}int main(){    n=read();k=read();    for (int i=1;i<n;i++)    {        int u=read(),v=read();        ins(u,v);ins(v,u);    }    dfs(1,0);    printf("%d",dp[1][0]);    return 0;}
原创粉丝点击