NC13611-树-(dp)
链接:https://ac.nowcoder.com/acm/problem/13611
来源:牛客网
题目描述
shy有一颗树,树有n个结点。有k种不同颜色的染料给树染色。一个染色方案是合法的,当且仅当对于所有相同颜色的点对(x,y),x到y的路径上的所有点的颜色都要与x和y相同。请统计方案数。
输入描述:
第一行两个整数n,k代表点数和颜色数; 接下来n-1行,每行两个整数x,y表示x与y之间存在一条边;
输出描述:
输出一个整数表示方案数(mod 1e9+7)。
备注:
对于30%的数据,n≤10, k≤3; 对于100%的数据,n,k≤300。
一直以为树的题目要用dfs解决,难得见到不用的。
n个点的树,看作一张连通图,任意两点路径上的点要相同颜色,也就是两点间的一片都要相同颜色,看作是一个连通分量,颜色有k种,任选多少种涂都行,在颜色上不做要求。
对于一个连通图,加上一个点,这个点的涂色方法,可以选择旧颜色和新颜色。
dp[i][j]表示i个点的联通图用j种颜色涂色的方案数量
对于第i个点,涂旧颜色即dp[i-1][j],涂新颜色即dp[i-1][j-1]*(k-(j-1));
dp[i][j]=dp[i-1][j]+dp[i-1][j-1]*(k-(j-1));
最后将n个点的连通图加起来就好。
#include<stdio.h> #include<iostream> #include<algorithm> #include<cstring> #include<math.h> #include<string> #include<map> #include<queue> #include<stack> #include<set> #define ll long long #define inf 0x3f3f3f3f using namespace std; const int p=1e9+7; ll dp[305][305]; int main()///NC13611 { int n,k; scanf("%d%d",&n,&k); memset(dp,0,sizeof(dp)); 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]%=p; } } ll ans=0; for(int i=1;i<=k;i++) ans=(ans+dp[n][i])%p; printf("%lld\n",ans); return 0; }