HDU 2068 RPG的错排(组合数的处理)

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
#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;
}





你可能感兴趣的:(递推)