暂无链接
树(tree)
【题目描述】
shy 有一颗树,树有 n 个结点。有 k 种不同颜色的染料给树染色。一个染色方案是合法 的,当且仅当对于所有相同颜色的点对(x,y),x 到 y 的路径上的所有点的颜色都要与 x 和 y 相同。请统计方案数。
【输入】
第一行两个整数 n,k 代表点数和颜色数;
接下来 n-1 行,每行两个整数 x,y 表示 x 与 y 之间存在一条边。
【输出】
输出一个整数表示方案数(mod 1e9+7)。
【输入样例】
4 3
1 2
2 3
2 4
【输出样例】
39
【提示】
【数据规模】
对于 30%的数据,n≤10, k≤3;
对于 100%的数据,n,k≤300。
题解
一看连暴力都打不来,以为自己要爆零了。。。
然而,事实上,因为树上的任意两个点都是可以两两联通的,而染色的过程就是构造联通快的过程,即将一颗树拆分成若干子树,所以这道题跟树的形态没有半毛钱关系orz。。。
于是,我们考虑使用dp,dp[i][j]表示用i个点染j种颜色的方案数。每一个点跟前一个点的关系只有颜色相同、颜色不同两种,当颜色相同时,该点的方案数等于上一个点方案数,不同时只能使用剩余的k−j+1k−j+1种颜色,于是我们可以得到状态转移方程:
dp[i][j]=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);
然而博主没开long long,期望得分100,实际得分30。。。
代码
#include<bits/stdc++.h>
using namespace std;
const int M=305;
const int mod=1e9+7;
int n,k,a;
long long dp[M][M];
void in()
{
scanf("%d%d",&n,&k);
for(int i=1;i<n;++i)
scanf("%d%d",&a,&a);
}
void ac()
{
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;
long long ans=0;
for(int i=1;i<=k;++i)
ans+=dp[n][i],ans%=mod;
printf("%lld",ans);
}
int main()
{
in();ac();
return 0;
}
本文介绍了一种利用动态规划解决树形结构中节点染色方案计数的问题。通过对树进行分解并使用DP[i][j]表示用i个点染j种颜色的方案数,实现了对树上节点进行有效染色方案的统计。
1109

被折叠的 条评论
为什么被折叠?



