1. 程式人生 > >卡特蘭數 斯特林數

卡特蘭數 斯特林數

這樣的 另一個 mes for 我們 。。 algo ret 數值

卡特蘭數\(C_{2n}^n - C_{2n}^{n-1}\)
還有常用的遞推:

int main() {
    scanf("%d", &n);
    f[0] = 1, f[1] = 1;
    for(int i=2; i<=n; i++) {
        for(int j=0; j<i; j++) {
            f[i] += f[j] * f[i-j-1];
        }
    }
    printf("%d", f[n]);
    return 0;
}

貌似很多題都是第0項為1,第一項為1,第二項為2,第三項為5這樣的

第一類斯特林數
\(S(n,k) = (n-1)*S(n-1,k) + S(n-1,k-1)\)

第二類斯特林數
\(S(n,k) = k*S(n-1,k) + S(n-1,k-1)\)
\(S(n,1) = 1 \ \ (n \geq1 )\)
\(S(n,n) = 1,S(n,0)=0\)
對於第二類斯特林數公式的推導:
若第n個元素單獨成一個集合,則有方案數\(S(n-1,k-1)\)
若n和別的元素成一個集合,那麽n可以放到k個集合中\(k*S(n-1,k)\)

第二類斯特林數,可以求出將n個元素的集合拆分為k個的非空集合的方案數(相當於把n個不同的小球放入m個不可區分,一模一樣的盒子裏)

例如,將6本不同的書分為三組,求方案數
答案是S(6,3),但我們還可以用別的方法做一下這道題
根據“先分組後分配”的思路,可以分為1,1,4;2,2,2;1,2,3三種情況
對於每種情況去重:
1,1,4\(C_6^4=C_6^2=15\),分完四本書,剩下的兩本自成一組(不用再除以\(A_2^2\)了)

如果你不信服的話,從另一個角度可以導出一樣的式子:\(\frac{C_6^4C_2^1}{A_2^2} = C_6^4\)(如果兩個式子在數值上相同,那麽這兩個式子各自的組合意義可能是解決某個問題的兩種思路
為什麽要除以\(A_2^2\)?假設有A書和B書,分為兩組(分組為:1,1),用\(C_2^1\)

來算,是兩種方案嗎?A B 和 B A是沒有差別的,所以只有一種方案。我們只是分組,而這裏組和組是一樣的,就像兩個一模一樣的盒子

2,2,2:同上,\(\frac{C_6^2C_4^2}{A_3^3} = 15\)

1,2,3\(C_6^3C_3^2 = 60\)

一共90種方案,而第二類斯特林數可以遞推求出:
x
1: 1
2: 1 1
3: 1 3 1
4: 1 7 6 1
5: 1 15 25 10 1
6: 1 31 90 65 15 1
7: 1 63 301 350 140 21 1
8: 1 127 966 1701 1050 266 28 1
9: 1 255 3025 7770 6951 2646 462 36 1
10: 1 511 9330 34105 42525 22827 5880 750 45 1
可得S(6,3) = 90

遞推程序(要是有錯的話,請在評論區指導一下我。。。)

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int MAXN = 3000 + 10;
int s[MAXN][MAXN],n;
int main() {
    scanf("%d", &n);
    for(int i=1; i<=n; i++) {
        s[i][1] = s[i][i] = 1;
        for(int j=1; j<i; j++) {
            s[i][j] = j * s[i-1][j] + s[i-1][j-1];
        }
    }
    printf("x\n");
    for(int i=1; i<=n; i++) {
        printf("%d: ",i);
        for(int j=1; j<=i; j++) {
            printf("%d ", s[i][j]);
        }
        puts("");
    }
    return 0;
}

卡特蘭數 斯特林數