1 2 0
1 1
#include<stdio.h> #include<string.h> #include<iostream> #include<algorithm> #include<math.h> 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<stdio.h> #include<string.h> #include<math.h> #include<algorithm> 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; }