有一系列值:
1 - n_1次
2 - n_2次
...
k - n_k次
这个节点有多少棵树?
我创造了简单的algorythm:
int get_count(const vector<int> n_i) {
if (n_i.size() <= 1) {
return 1;
} else {
int total_count = 0;
for (int i = 0; i < n_i.size(); ++i) {
vector<int> first;
vector<int> second;
for (int j = 0; j < i; ++j) {
first.push_back(n_i[j]);
}
if (n_i[i] != 1) {
second.push_back(n_i[i] - 1);
}
for (int j = i + 1; j < n_i.size(); ++j) {
second.push_back(n_i[j]);
}
total_count += (get_count(first) * get_count(second));
}
return total_count;
}
}
因为
#(n_1,n_2,... n_k)=#(n_1 - 1,n_2,...,n_k)+#(n_1)#(n_2 - 1,... n_k)+ ... + #(n_1,...,n_k - 1)
和
#(0,n_i,n_j,...)=#(n_i,n_j,...)
但我的代码太慢了。
例如,根据Cathalan的数字是否有最终公式?
答案 0 :(得分:1)
我猜这个问题可以分解为计算排列数和计算给定大小的二叉树数量。我将我的初始递归Java代码(放弃n1 = 10,n2 = 10,n3 = 10)转换为这个迭代的代码:
static int LIMIT = 1000;
static BigInteger[] numberOfBinaryTreesOfSize = numberOfBinaryTreesBelow(LIMIT);
static BigInteger[] numberOfBinaryTreesBelow(int m) {
BigInteger[] arr = new BigInteger[m];
arr[0] = BigInteger.ZERO;
arr[1] = arr[2] = BigInteger.ONE;
for (int n = 3; n < m; n++) {
BigInteger s = BigInteger.ZERO;
for (int i = 1; i < n; i++)
s = s.add(arr[i].multiply(arr[n - i]));
arr[n] = s;
}
return arr;
}
static BigInteger[] fac = facBelow(LIMIT);
static BigInteger[] facBelow(int m) {
BigInteger[] arr = new BigInteger[m];
arr[0] = arr[1] = BigInteger.ONE;
for (int i = 2; i < m; i++)
arr[i] = arr[i - 1].multiply(BigInteger.valueOf(i));
return arr;
}
static BigInteger getCountFast(int[] arr) {
// s: sum of n_i
int s = 0; for (int i = 0; i < arr.length; i++) { s += arr[i]; }
// p: number of permutations
BigInteger p = fac[s]; for (int i = 0; i < arr.length; i++) { p = p.divide(fac[arr[i]]); }
BigInteger count = p.multiply(numberOfBinaryTreesOfSize[s]);
return count;
}
public static void main(String[] args) {
System.out.println(getCountFast(new int[]{ 150, 150, 150, 150, 150 }));
}
LIMIT
限制了n_i的总和。上面的例子在我的机器上大约需要两秒钟。也许它可以帮助您使用C ++解决方案。