[USACO2.3]奶牛家谱 Cow Pedigrees
题目
思路
dp,开始随便写了个dfs结果得了33分。看标签发现是dp,然后发现dp确实可行。(一下方法应该不是最优的)
d
p
[
i
]
[
k
]
代
表
节
点
数
目
为
i
深
度
为
k
的
结
构
数
,
转
移
方
程
如
下
:
dp[i][k]代表节点数目为i深度为k的结构数,转移方程如下:
dp[i][k]代表节点数目为i深度为k的结构数,转移方程如下:
d
p
[
i
]
[
k
]
=
∑
m
=
1
k
−
1
∑
j
=
1
i
−
2
f
∗
d
p
[
j
]
[
k
−
1
]
∗
d
p
[
i
−
1
−
j
]
[
m
]
dp[i][k] =\sum_{m=1}^{k-1}\sum _{j=1}^{i-2}f*dp[j][k-1]*dp[i-1-j][m]
dp[i][k]=m=1∑k−1j=1∑i−2f∗dp[j][k−1]∗dp[i−1−j][m]
其中
j
∈
[
1
,
i
−
2
]
,
m
∈
[
1
,
k
−
1
]
,
f
=
1
+
(
k
−
1
=
=
m
?
0
:
1
)
j \in[1,i-2],m\in[1,k-1],f=1+(k-1==m\ ?\ 0:1)
j∈[1,i−2],m∈[1,k−1],f=1+(k−1==m ? 0:1)
解释如下:对于一个具有i个节点的高度为k的树,我们考虑其构成,可能是有一个具有j个节点的深度为的k-1左子树和具有i-1-j个节点的高度为m(m<=k-1)的右子树构成,当然也可以把这两个子树的位置对调。所以当两边子树高度不等的时候直接乘以2,就是所有方案。
#include <iostream>
using namespace std;
const int mod = 9901;
#define rep(i, a, b) for (int i = a; i < b; i++)
#define rep_(i, a, b) for (int i = a; i <= b; i++)
int n, k;
int dp[210][110];
int main() {
cin >> n >> k;
dp[1][1] = 1;
rep_(i, 2, n) {
rep_(h, 1, (i-1)/2+1) {
rep_(j, 1, i-2) {
rep_(m, 1, h-1) {
int f = 1;
if (m != h-1) f = 2;
dp[i][h] = (dp[i][h] + f * dp[j][h-1] * dp[i-1-j][m]) % mod;
}
}
}
}
cout << dp[n][k] << endl;
return 0;
}