我一直在研究USACO培训问题Cow Pedigrees(有关问题的解释和示例解决方案,请参见https://jvonk.github.io/usaco/2018/10/16/nocows.html)
基本上,你必须计算节点数为N,高度为K的唯一二叉树的可能性的数量(mod 9901)。
下面是我目前为止尝试过的C++代码。它输出一些较小输入的正确答案,如N = 5; K = 3和N = 9;然而,一旦它到达N = 35和K = 7的测试用例,它就输出7642而不是5024的正确答案。
我一生都无法弄清楚为什么会这样,因为我的代码对我来说都是有意义的,当我用较小的数字完成这些步骤时,它似乎一切都正确,就像我手动完成一样。我认为这个问题与它有关,重复计算不应该被重复计算的可能性(在if else语句中),但我不知道为什么这是真的。
如果有人能解释一下我的方法哪里出错了,以及我如何纠正它,我将非常感激!先谢谢你了
#include <bits/stdc++.h>
using namespace std;
int main() {
// values
int N, K;
int possibilities[201][101]{};
// input
ifstream fin("nocows.in");
fin >> N >> K;
// solution
possibilities[1][1] = 1;
for (int k = 2; k <= K; k++){ // for every possible height
// 1 node is used for the "mother", the amount of the rest of the nodes will be between 2*(k - 1) and -2 * (1-2^(k-1))
for (int n = 2 * (k - 1); n <= 2 * (pow(2, k - 1) - 1) && n <= N; n += 2 ){
// one side will have n1 nodes - anywhere odd number from 1 to n; and a height of k - 1
for (int n1 = 1; n1 < n; n1 += 2){
// the other side will have any height k - 1 or less and the remaining nodes
for (int k1 = 1; k1 < k; k1++){
// if they are different numbers, they will be doubled because they are not interchangable so can work for both right and left
if (n1 != n - n1 || k1 != k - 1)
possibilities[n + 1][k] += (2 * possibilities[n1][k - 1] * possibilities[n - n1][k1]) % 9901;
else
possibilities[n + 1][k] += (possibilities[n1][k - 1] * possibilities[n - n1][k1]) % 9901;
possibilities[n + 1][k] %= 9901;
}
}
}
}
// output
ofstream fout("nocows.out");
fout << possibilities[N][K] % 9901 << '\n';
return 0;
}
1条答案
按热度按时间pengsaosao1#
你可以简化你的思维方式,把原来的问题分解成两个更小的问题。
在这个树中,每个节点要么总是有两个孩子,要么没有孩子。因此,根(您称之为“母亲”)要么有两个孩子,要么没有孩子。有零个孩子的根是平凡的。它对应于N = 1和K = 1。
当根有两个孩子时,这些孩子中的每一个都可以是它们自己的树的根。仔细看看这些子树。这些树彼此完全独立。它们中的每一个都以与原始树相同的方式运行。只要它们中的一个具有k-1的深度,它们一起形成原始树的有效排列。
因此,您的代码应该通过以下方式简化:
n1
不必是奇数。它可以是任何数字<= n-1
。另一棵树将有n2 = n - 1 - n1
个节点。记住,已经有一个根节点,即n1 + n2 = n-1
。n1
、n2
、k1
和k2
。k1
和k2
是两个子树的深度。k1
和k2
中至少有一个等于k-1
。只有这样,您才能获得与原始树相对应的配置。(k1 == k-1) && (k2 == k-1)
的情况,不要重复计算它。修改给定代码的一种方法是: