牛客网 Wannafly模拟赛2 树 dp+思维

来源:互联网 发布:angelababy百花奖知乎 编辑:程序博客网 时间:2024/06/07 11:07

题目链接


题意:


shy有一颗树,树有n个结点。有k种不同颜色的染料给树染色。一个染色方案是合法的,当且仅当对于所有

相同颜色的点对(x,y),x到y的路径上的所有点的颜色都要与x和y相同。请统计方案数。


思路:

这个题真的很不好想,只要想到了就很简单了,当然我也没想,因为没机会啊大哭

 

根据题意的描述,所有被染成同一个颜色的都是一个连通图,也就是很多个子树,你将这棵树用多少种颜色染色,拆分

出来之后就会有多少个子树,每个子树当中节点的颜色一样.

那么我们就可以用dp来简单计数,dp[i][j] 表示 i个点染成j个颜色的方案数.那么有:

dp[i][j] = dp[i-1][j]+dp[i-1][j-1]*(k-(j-1))

即第i个点要么和第i-1个点颜色相同,要么不同,不同的话前面用过的颜色都不能用了,还剩k-j+1种颜色.


PS : 也可以这样想,你把n个点,按照颜色相同的看成一个连通块,总能对应树上的一种染色方法,每一个连通块就是子树.

#include<bits/stdc++.h> using namespace std; const int maxn = 333;typedef long long ll;const ll mod = 1e9 + 7; ll dp[maxn][maxn];int n,k;int main(){    while(~scanf("%d %d",&n,&k))    {        memset(dp,0,sizeof dp);        int a,b;        for(int i = 1;i < n;i++)        scanf("%d %d",&a,&b);        dp[0][0] = 1;        for(int i = 1;i <= n;i++)        {            for(int j = 1;j <= k;j++)            {                dp[i][j] = dp[i-1][j] + dp[i-1][j-1]*(k - j + 1);                dp[i][j] %= mod;            }        }        ll ans = 0;        for(int i = 1;i <= k;i++)        ans = (ans + dp[n][i]) % mod;        printf("%lld\n",ans);    }}

原创粉丝点击