#include
#include
#include
#include
#include
using namespace std;
int C(int n, int m) // 求 C(n,m)
{
__int64 t = 1;
__int64 tmp = 1;
for(int i = 1; i <= m; ++i)
{
tmp *= (n - i + 1);
t *= i;
}
return tmp / t;
}
int main()
{
long long a[28], sum, t;
int n,i;
while(scanf("%d", &n) && n)
{
sum = 1;
a[1] = 0;
a[2] = 1;
for(i = 3; i <= n; i++)
a[i] = (i - 1) * (a[i - 2] + a[i - 1]);
for(i = 1; i <= n / 2; i++)
sum += a[i] * C(n,i);
printf("%lld\n",sum);
}
return 0;
}
PS:刚开始直接用阶乘,调用求组合数,一直不对,网上看了下代码,觉得可能是数据溢出了。有必要总结下如何求组合数.
我们用 C(n,r) 来表示组合数,代表从n个不同小球里取出r个小球的取法。
第一种根据公式而来。在数学中,
C(n,r) = n*(n-1)*(n-2)*...*(n-r+1)/r! (这个都知道,这个题用这个方法) (PPS:不可以运用n! / ((r!)(n-r)!) 数据竟然错了!!!!溢出或者是不能整除了)
这是直接运算的公式,写成代码的话循环r次就可以得到分子分母,然后相除。这种方法的毛病就是求分子分母的数可能太大了,计算时浪费了很多内存。当然也可先除,再乘起来,不过如果恰好对应的两个数不能整除就麻烦了。
下面是几个百度方法(PPPS: 好厉害的样子~~~~~~~~)
(1)利用递推关系式C(n,m) = C(n-1,m) + C(n-1,m-1)来实现
(2)n*(n-1)*(n-2)*...*(n-r+1)/r! 变形 n * (n - 1)/ 1 * (n - 2) / 2 。。。。。。。就是每次先除去,然后在乘。
(3)还有很多种,学习内容有限(能用DP做),以后添加吧~~~~~~~
测试代码(用递推50以内是能求出来的)
#include
#include
#include
#include
using namespace std;
int C(int n, int m) // Çó C(n,m)
{
__int64 t = 1;
__int64 tmp = 1;
for(int i = 1; i <= m; ++i)
{
tmp *= (n - i + 1);
t *= i;
}
return tmp / t;
}
int main()
{
long long a[100], b[100][100];
int n, i, j;
while(scanf("%d",&n) != EOF)
{
for(i = 1; i <= n ; i++)
a[i] = C(n,i);
printf("Case 1:\n");
for(i = 1; i <= n; i++)
printf("C(%d,%d) = %lld \n",n, i, a[i]);
printf("\n");
for(i=0; i<=n; ++i)
{
b[0][i] = 0;
b[i][0] = 1;
}
for(i=1; i<=n; ++i)
{
for(j=1; j<=n; ++j)
b[i][j] = (b[i-1][j] + b[i-1][j-1]);
}
printf("Case 2:\n");
for(i = 1; i <= n; i++)
printf("C(%d,%d) = %lld\n",n, i, b[n][i]);
printf("\n");
}
return 0;
}