1. 程式人生 > >HDU1023——Train Problem II(卡特蘭數)

HDU1023——Train Problem II(卡特蘭數)

=======================================================================

卡特蘭數

卡特蘭數又稱卡塔蘭數,是組合數學中一個常出現在各種計數問題中出現的數列。由以比利時的數學家歐仁·查理·卡塔蘭 (1814–1894)命名。

卡特蘭公式的應用很廣泛,最典型的四種應用問題現描述如下:

1.括號化問題。   矩陣鏈乘: P=a1×a2×a3×……×an,依據乘法結合律,不改變其順序,只用括號表示成對的乘積,試問有幾種括號化的方案?(h(n)種) 2.出棧次序問題。

  一個棧(無窮大)的進棧序列為1,2,3,..n,有多少個不同的出棧序列?

  類似:有2n個人排成一行進入劇場。入場費5元。其中只有n個人有一張5元鈔票,另外n人只有10元鈔票,劇院無其它鈔票,問有多少中方法使得只要有10元的人買票,售票處就有5元的鈔票找零?(將持5元者到達視作將5元入棧,持10元者到達視作使棧中某5元出棧)

3.將多邊行劃分為三角形問題。

  將一個凸多邊形區域分成三角形區域的方法數?

  類似:一位大城市的律師在她住所以北n個街區和以東n個街區處工作。每天她走2n個街區去上班。如果她從不穿越(但可以碰到)從家到辦公室的對角線,那麼有多少條可能的道路?

      類似:在圓上選擇2n個點,將這些點成對連線起來使得所得到的n條線段不相交的方法數?

4.給頂節點組成二叉樹的問題。

  給定N個節點,能構成多少種不同的二叉樹?

Catalan數的解法

1.Catalan數的組合公式為 Cn=C(2n,n) / (n+1); 2.此數的遞迴公式為 h(n ) = h(n-1)*(4*n-2) / (n+1)。 令h(1)=1,h(0)=1,catalan數滿足遞迴式:   h(n)= h(0)*h(n-1)+h(1)*h(n-2) + ... + h(n-1)h(0) (其中n>=2)   例如:h(2)=h(0)*h(1)+h(1)*h(0)=1*1+1*1=2   h(3)=h(0)*h(2)+h(1)*h(1)+h(2)*h(1)=1*2+1*1+2*1=5   另類遞迴式:   h(n)=h(n-1)*(4*n-2)/(n+1);

  該遞推關係的解為:   h(n)=C(2n,n)/(n+1) (n=1,2,3,...)

如果說這不夠你塞牙縫,那就來看看這裡吧點選填飽肚子

來,咱們迴歸正題,怎麼解決這道題,中國人看問題一般最先看肯本問題,而解決這道題的根本就是大數的乘除運算:

大數運算,所謂大數,就是你都不知道它怎麼讀的數,比如10000的階乘有3w多位,你應該是從前面讀呢,還是從後面的個位數呢?

想想咱們平時怎麼算乘除的,這裡就是怎麼算的:

假設用a[]陣列來倒敘儲存一個數(23存進去就是32),a[0]代表這個數的長度,a[1]是個位,a[2]是十位。。。現在開始算,假如用23*16,咱們先int yu=0,len=2,也就是餘數現在是0,23的長度是2,先從個位算起,3*16 = 48, 那麼算出來個位就是8,那怎麼辦呢,先給餘數yu=4,再算2*16=32,然後32+yu=36,這時a[2]=6,那3怎麼辦呢,當然是給餘數啦yu=3,由於已經乘完了那麼3直接放到a[3]=3;得數就是a[3]a[2]a[1](368),別忘了a[0] = 3(長度);這就是神奇的乘法。

再想想咱們平時怎麼算除法的:

假設用a[]存一個225(a[0]=3,a[1]=5,a[2]=2,a[3]=2),除數為25,現在開始算,int yu=0,len=3; 這次從陣列a的最後一位算起,a[len]/25=0;那麼a[len] = 0,然後把餘數存進yu=2,再算下一位,(a[2]+10*yu)/25 = 0,a[len-1] = 0, yu = 22, (a[1]+10*yu)/25 = 9, a[1] = 9, yu = 0,這時a[3]=0,a[2]=0,a[1]=9,別忘了a[0]=1於是商=9;

好了看程式碼吧:

程式碼實現:

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>

using namespace std;
typedef long long LL;
const int maxn = 1000000+10;
const int inf = -0x7fffffff;
int a[maxn];
int pre[maxn];
int now[maxn];
int MAX;

int main()
{
    int m, n;
    while( ~scanf("%d%d",&m,&n) )
    {
        memset(a,0,sizeof(a));
        memset(pre,0,sizeof(pre));
        memset(now,0,sizeof(now));
        int i,j;
        for( i=1; i<=n; i++ )
            scanf("%d",&a[i]);
        for( i=1; i<=m; i++ )
        {
            MAX = inf;
            for( j=i; j<=n; j++ )
            {
                now[j] = max(now[j-1]+a[j], pre[j-1]+a[j]);
                pre[j-1] = MAX;
                MAX = max(MAX, now[j]);
            }
        }
        printf("%d\n",MAX);
    }
    
    return 0;
}