【POJ】2084Game of Connections(大数的卡特兰数处理)

Time Limit: 1000MS   Memory Limit: 30000K
Total Submissions: 9193   Accepted: 4506

Description

This is a small but ancient game. You are supposed to write down the numbers 1, 2, 3, . . . , 2n - 1, 2n consecutively in clockwise order on the ground to form a circle, and then, to draw some straight line segments to connect them into number pairs. Every number must be connected to exactly one another. 
And, no two segments are allowed to intersect. 
It's still a simple game, isn't it? But after you've written down the 2n numbers, can you tell me in how many different ways can you connect the numbers into pairs? Life is harder, right?

Input

Each line of the input file will be a single positive number n, except the last line, which is a number -1. 
You may assume that 1 <= n <= 100.

Output

For each n, print in a single line the number of ways to connect the 2n numbers into pairs.

Sample Input

2
3
-1

Sample Output

2
5

Source

Shanghai 2004 Preliminary

题目大意:给你一个n,然后你用2*n围成一个圈圈,按顺序来,就比如:

扫描二维码关注公众号,回复: 2778050 查看本文章

n=2是=时:

就是这样子;然后开始讨论:

1.当n=1时;

就只有这一种,所以可以说是f(1)=1

2.当n=2时

这次就有一些了:共有四个数看看他们的组合吧

(1)1-2相连,那么另外的 3和4 位于线段的一侧,他们可以相连,也只能让他们相连,这是一种

(2)1-3相连,另外的2和3 不能相连,这不满足题目要求,放弃这种。

(3)1-4相连,情况与第一种基本相同,这也是一种。

那么全部情况就是这三种,加起来的话,共两种可行情况,f(2)=2

同样的,在这里我们可以得出一个结论:

1与奇数数字连线时,将不具有满足题意的结果。因为连线后,相当于把圆分成了两个区域,而如果某个区域内有奇数个数字,那么必定有1个数字要与其他区域的数字相连,这样就一定会产生相交的连线。如n=2,当1与3连线后,分成了两个区域,一个区域含有数字2,一个区域含有数字4,它们要构成线段必定要与其他的线段产生交点。

所以下面的例子就只与偶数数字相连了

3.当n=3时

共有六个数字,看一下下面的情况

 (1)1-2相连,那么下面圈子里的情况,就无需多算,四个自然数顺序排列的情况我们在上一步已经算完了

                 这一步的结果就是1*f(2)也就是f(1)*f(2)

(2)1-4相连,这种情况也是只有一种的

(3)1-6相连,这种情况与(1)基本类似,

这一步的方案数加起来共五种,也就是f(3)=5;

4.当n=4时

共有八个数字,看一下情况

这种的,

f(4) = f(3) + f(1) * f(2) + f(2) * f(1) + f(3) = 5 + 1 x 2 + 1 x 2 + 5 = 14种。

下面的就不举例子了。

f(1) = 1

f(2) =f(1) * f(0) + f(0) *f(1)

f(3) = f(2) * f(0) + f(1) * f(1) + f(0) * f(2)

f(4) = f(3) * f(0) + f(2) *f(1) + f(1) *f(2) + f(0) *f(3)

然后推出这东西就是卡特兰数,

因为他满足卡特兰数的第一个递推公式;

h(n)=C(n,2n)/(n+1)=(2n)!/((n!)*(n+1)!) = C(n, 2n) - C(n +1, 2n)

可以看一下我这篇博客,有关卡特兰数总结的,

下面就是代码:

#include<iostream>
using namespace std;
int cal[109][109]; ///卡特兰数cal[i][j];i代表第i个卡特兰数,j代表当前卡特兰数的第j位
int len[109]; ///用于存储各个卡特兰数的长度

void getCal()
{
    len[1] = 1;
    cal[1][0] = 1;

    int carry;  ///用于控制进位
    int temp;
    int tempLen = 1;
    for(int i=2;i<=100;i++)
    {
        for(int j=0;j<tempLen;j++)  ///先进行相乘
        {
            cal[i][j] = (4*i-2)*cal[i-1][j];
        }
        carry = 0;
        for(int j=0;j<tempLen;j++)  ///把各个数分配的不同的位上
        {                           ///与手算乘法的道理一样:从低位往高位算
            temp = carry + cal[i][j];
            cal[i][j] = temp%10;
            carry = temp/10;
        }

        while(carry)
        {
            cal[i][tempLen++] = carry%10;
            carry /= 10;
        }

        carry = 0;

        for(int j=tempLen-1;j>=0;j--)  ///处理除法,与手算除法的道理一样:从高位往低位算
        {
            temp = carry*10 + cal[i][j];
            cal[i][j] = temp/(i+1);
            carry = temp%(i+1);
        }

        while(cal[i][tempLen-1]==0)  ///如果最高位是0的话,则不算数
        {
            tempLen --;
        }

        len[i] = tempLen;
    }
}
int main()
{
    getCal();
    int n;
    while(cin>>n)
    {
        if(-1==n)
        {
            break;
        }
        for(int i=len[n]-1;i>=0;i--)
        {
            cout<<cal[n][i];
        }
        cout<<endl;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/wentong_Xu/article/details/81700208
今日推荐