您的位置:首页 > 其它

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

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: