hoj1294

用dfs进行整数拆分,对于每种情况计算组合数。为了避免重复计算,必须使用有重集的组合,com(f[i] - 1 + num[i], num[i]),这是num[i]个有i个节点的子树的情况总数。这个公式是用于求所选物品可重复选择,且重复选出的同一物品完全相同的情况。

View Code
#include <iostream>
#include
<cstdio>
#include
<cstdlib>
#include
<cstring>
#include
<cmath>
using namespace std;

#define maxn 41

long long f[maxn], num[maxn], ans;
int n;

long long com(long long n, long long r)
{
// return C(n, r)
if (n - r < r)
r
= n - r; // C(n, r) = C(n, n-r)
long long i, j, s = 1;
for (i = 0, j = 1; i < r; ++i)
{
s
*= (n - i);
for (; j <= r && s % j == 0; ++j)
s
/= j;
}
return s;
}
long long gcd(long long a, long long b)
{
return b?gcd(b,a%b):a;
}

long long C(long long n, long long m)
{
if(m > n - m ) m = n - m;
long long mul = 1 , div = 1;
for(int i = 0; i < m;i++)
{
mul
*= (n-i);
div
*= (i+1);
long long g = gcd(mul,div);
mul
/=g , div /= g;
}
return mul / div;
}


void dfs(int s, int left)
{
if (left == 0)
{
ans
= 1;
for (int i = 0; i <= n; i++)
if (num[i] != 0)
ans
*= com(f[i] - 1 + num[i], num[i]);
f[n]
+= ans;
}
if (s > left)
return;
num[s]
++;
dfs(s, left
- s);
num[s]
--;
dfs(s
+ 1, left);
}

int main()
{
//freopen("D:\\t.txt", "r", stdin);
//freopen("D:\\y.txt", "w", stdout);
memset(num, 0, sizeof(num));
f[
1] = 1;
f[
2] = 1;
for (n = 3; n <= 40; n++)
{
dfs(
1, n - 1);
//printf("f[%d]=%I64d;", n, f[n]);
}
while (scanf("%d", &n) != EOF)
printf(
"%I64d\n", f[n]);
return 0;
}
原文地址:https://www.cnblogs.com/rainydays/p/1988842.html