HDU 2068 RPG的错排(组合数的处理)
2015-07-25 08:11
246 查看
Problem Description
今年暑假杭电ACM集训队第一次组成女生队,其中有一队叫RPG,但做为集训队成员之一的野骆驼竟然不知道RPG三个人具体是谁谁。RPG给他机会让他猜猜,第一次猜:R是公主,P是草儿,G是月野兔;第二次猜:R是草儿,P是月野兔,G是公主;第三次猜:R是草儿,P是公主,G是月野兔;......可怜的野骆驼第六次终于把RPG分清楚了。由于RPG的带动,做ACM的女生越来越多,我们的野骆驼想都知道她们,可现在有N多人,他要猜的次数可就多了,为了不为难野骆驼,女生们只要求他答对一半或以上就算过关,请问有多少组答案能使他顺利过关。
Input
输入的数据里有多个case,每个case包括一个n,代表有几个女生,(n<=25), n = 0输入结束。
Sample Input
Sample Output
Author
Rabbit
代码如下:
我们用 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以内是能求出来的)
今年暑假杭电ACM集训队第一次组成女生队,其中有一队叫RPG,但做为集训队成员之一的野骆驼竟然不知道RPG三个人具体是谁谁。RPG给他机会让他猜猜,第一次猜:R是公主,P是草儿,G是月野兔;第二次猜:R是草儿,P是月野兔,G是公主;第三次猜:R是草儿,P是公主,G是月野兔;......可怜的野骆驼第六次终于把RPG分清楚了。由于RPG的带动,做ACM的女生越来越多,我们的野骆驼想都知道她们,可现在有N多人,他要猜的次数可就多了,为了不为难野骆驼,女生们只要求他答对一半或以上就算过关,请问有多少组答案能使他顺利过关。
Input
输入的数据里有多个case,每个case包括一个n,代表有几个女生,(n<=25), n = 0输入结束。
Sample Input
1 2 0
Sample Output
1 1
Author
Rabbit
代码如下:
#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 [i]); printf("\n"); } return 0; }
相关文章推荐
- Frameworks(不定时更新)
- Scala并发编程匿名Actor、消息传递、偏函数实
- 【LeetCode-面试算法经典-Java实现】【028-Implement strStr() (实现strStr()函数)】
- getActionBar();null问题
- ios 最全的常用字符串操作
- 源泉书签, 全新表格,非凡体验
- uva 10034 Freckles 最小生成树
- 数组和指针有关sizeof的题目
- 【LeetCode-面试算法经典-Java实现】【027-Remove Element(删除数组中指定的元素)】
- poj-3764 The xor-longest Path
- vi/vim编辑器的使用
- poj 1258 Agri-Net 最小生成树
- 微软语出惊人 Windows 10没有正式版和RTM版
- hadoop-mapreduce在maptask执行分析
- ]Odoo(OpenERP)应用实践: 使用db-filter参数实现通过域名指定访问哪个数据库
- linux的sh脚本编程
- 如何使用SSH连接OpenStack上的云主机
- stringstream缓存正确清除方法
- poj 1679 The Unique MST - 次小生成树
- 10行Java代码实现最近被使用(LRU)缓存