卡特兰数的模型,HDU 1134 Game of Connections

卡特兰数:

1 通项公式:h(n)=C(n,2n)/(n+1)=(2n)!/((n!)*(n+1)!)

2递推公式:h(n)=((4*n-2)/(n+1))*h(n-1); h(n)=h(0)*h(n-1)+h(1)*h(n-2)+...+h(n-1)*h(0).

3前几项为:h(0)=1,h(1)=1,h(2)=2,h(3)=5,h(4)=14,h(5)=42,......

4应用场景:

a.括号化问题。
  矩阵链乘: P=a1×a2×a3×……×an,依据乘法结合律,不改变其顺序,只用括号表示成对的乘积,试问有几种括号化的方案?(h(n)种)
b.出栈次序问题。
  一个栈(无穷大)的进栈序列为1,2,3,..n,有多少个不同的出栈序列?
  类似:
  (1)有2n个人排成一行进入剧场。入场费5元。其中只有n个人有一张5元钞票,另外n人只有10元钞票,剧院无其它钞票,问有多少中方法使得只要有10元的人

      买 票,售票处就有5元的钞票找零?(将持5元者到达视作将5元入栈,持10元者到达视作使栈中某5元出栈)
  (2)在圆上选择2n个点,将这些点成对连接起来,使得所得到的n条线段不相交的方法数。

c.将多边行划分为三角形问题。
  (1)将一个凸多边形区域分成三角形区域的方法数?
  (2)类似:一位大城市的律师在她住所以北n个街区和以东n个街区处工作。每天她走2n个街区去上班。如果她从不穿越(但可以碰到)从家到办公室的对角线,那            么有多少条可能的道路?
  (3)类似:在圆上选择2n个点,将这些点成对连接起来使得所得到的n条线段不相交的方法数?
d.给顶节点组成二叉树的问题。
  给定N个节点,能构成多少种形状不同的二叉树?
  (一定是二叉树!先去一个点作为顶点,然后左边依次可以取0至N-1个相对应的,右边是N-1到0个,两两配对相乘,就是

      h(0)*h(n-1) + h(2)*h(n-2) +  + h(n-1)h(0)=h(n))(能构成h(N)个)。

以上内容摘自: http://www.cnblogs.com/buptLizer/archive/2011/10/23/2222027.html

Game of Connections

 HDU - 1134 

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

题意:2n个人围成一个圆圈,求两两相互握手并且不交叉的所有握手方式。
这个是卡特兰数的一个例子,设2n个人一共有h(n)种,那么现在第一个人可以和第2,4,6,。。。,2(n-1),2n,即必须保证和他握手的那个人两边是偶数,即为:,h(0)=1,h(1)=1.
h(n)=h(0)*h(n-1)+h(1)*h(n-2)+...+h(n-1)*h0=(4*n-2)/(n+1) *h(n-1)
通项公式:h(n)=C(n,2n)/n+1=(2n)!/((n!)*(n+1)!)
但是这个题目是大数,所以必须采用数组模拟乘除法. 用此公式:h(n)=h(n-1)*(4*n-2)/(n+1);

代码是自己敲的,因为敲的bug非常多,调了好一会儿,所以来存一下代码 0.0 

#include <iostream>
#include <cstring>
#include <cstdio>
#include <math.h>
#include <map>
#include <queue>
#include <algorithm>
#define mem(a,b) memset(a,b,sizeof(a))
#define inf 0x3f3f3f3f
typedef long long LL;
const LL mod=1e9+7;
using namespace std;
const int N=1e2+100;
int a[N][N];
//a[i][0]存的是第i个数字的长度,a[i][1]是数字的最低位,a[i][ a[i][0] ]是数字的最高位
void init()
{
    mem(a,0);
    a[0][0]=1;
    a[0][1]=1;
    a[1][0]=1;
    a[1][1]=1;
    for(int i=2; i<=100; i++)
    {
        int z=4*i-2,r=0,p;
        a[i][0]=a[i-1][0];
        for(int j=1; j<=a[i][0]; j++)//乘以(4*i-2)
        {
            p=a[i-1][j]*z+r;
            a[i][j]=p%10;
            r=p/10;
        }
        while(r)
        {
            a[i][++a[i][0]]=r%10;
            r=r/10;
        }
        z=i+1,r=0;
        for(int j=a[i][0]; j>=1; j--)//除以(i+1)
        {
            p=(r*10+a[i][j])/z;
            r=(r*10+a[i][j])%z;
            a[i][j]=p;
        }
        while(a[i][a[i][0]]==0) a[i][0]--;//去掉最高位的0
    }
}
int main()
{
    init();
    int n;
    while(~scanf("%d",&n)&&n!=-1)
    {
        for(int j=a[n][0]; j>=1; j--)
            printf("%d",a[n][j]);
        printf("\n");
    }
}

猜你喜欢

转载自blog.csdn.net/xiangaccepted/article/details/81142909
今日推荐