Loading

球盒模型

参考

算法学习笔记(7):球盒模型

斯特林数 - OI Wiki

贝尔数 - OI Wiki

基本模型

球盒模型可根据:

  • 球与球之间是否相同
  • 盒子与盒子之间是否相同
  • 盒子是否能为空

分为\(2^3=8\)种基本模型

n个相同的球,k个相同的盒子,盒子可为空

int box0(int n, int k) {
    if (!n) return 1;
    if (!k) return 0;
    if (n < k) return box0(n, n);
    return box0(n - k, k) + box0(n, k - 1);
}

n个相同的球,k个相同的盒子,盒子不为空

int box1(int n, int k) {
    if (n < k) return 0;
    return box0(n - k, k);
}

n个相同的球,k个不相同的盒子,盒子可为空

隔板法:

考虑将\(k-1\)个隔板插入\(n\)个小球中,转换成隔板插入的方案数

将木板和隔板都当作物品,即将\(n+k-1\)个物品中选出\(k-1\)个作为隔板,方案数为\(C_{n+k-1}^{k-1}\)

const int N = 1010, mod = 1e9 + 7;
ll c[N][N];

void initC() {
    c[0][0] = 1;
    for (int i = 1; i <= 1000; ++ i) {
        c[i][0] = 1;
        for (int j = 1; j <= 1000; ++ j)
            c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % mod;
    }
}

int box2(int n, int k) {
    return c[n + k - 1][k - 1];
}

n个相同的球,k个不相同的盒子,盒子不可为空

隔板法:

隔板只能插入球与球的间隔,方案数为\(C_{n - 1}^{k-1}\)

int box3(int n, int k) {
    return c[n - 1][k - 1];
}

n个不相同的球,k个相同的盒子,盒子可为空

从第二类斯特林数考虑:

盒子是相同的,考虑通过枚举一共几个非空盒子,即\(\sum_{k=0}^{n}{n \brace k}\)

int box4(int n, int k) {
    ll res = 0;
    for (int i = 1; i <= k; ++ i) res = (res + s[n][i]) % mod;
    return res;
}

特别的当\(n \leq k\)时,答案为贝尔数,记作\(B_{n}\)

\[B_{n+1}=\sum_{k=0}^{n}C_{n}^{k}B_{k} \]

\(B_{n+1}\)\(B_{n}\)多一个元素\(a_{n+1}\),考虑:

  • 若这个元素单独划分为一类,剩下\(n\)个元素,共\(C_{n}^{0}B_{n}\)种方案
  • 若这个元素与另一个元素划分成一类,剩下\(n-1\)个元素,共\(C_{n}^{1}B_{n-1}\)种方案
  • 若这个元素与另两个元素划分成一类,剩下\(n-2\)个元素,共\(C_{n}^{2}B_{n-2}\)种方法
  • \(\cdots \cdots\)

贝尔数可通过贝尔三角形计算

\[\begin{aligned} & 1 \\ & 1\quad\qquad 2 \\ & 2\quad\qquad 3\quad\qquad 5 \\ & 5\quad\qquad 7\quad\qquad 10\,\,\,\qquad 15 \\ & 15\,\,\,\qquad 20\,\,\,\qquad 27\,\,\,\qquad 37\,\,\,\qquad 52 \\ & 52\,\,\,\qquad 67\,\,\,\qquad 87\,\,\,\qquad 114\qquad 151\qquad 203\\ & 203\qquad 255\qquad 322\qquad 409\qquad 523\qquad 674\qquad 877 \\ \end{aligned} \]

  • \(a_{0,0}=1\)
  • \(a_{n,1}=a_{n-1,n-1}\)
  • \(a_{n,m}=a_{n,m-1}+a_{n-1,m-1}\)

\(a_{n,1}\)即为\(B_{n}\)

void initBell(int n) {
    bell[0][0] = 1;
    for (int i = 1; i <= n; ++ i) {
        bell[i][0] = bell[i - 1][i - 1];
        for (int j = 1; j <= n; ++ j)
            bell[i][j] = (bell[i][j - 1] + bell[i - 1][j - 1]) % mod;
    }
}

n个不相同的球,k个相同的盒子,盒子不可为空

第二类斯特林数(斯特林子集数)\(n \brace k\),也记作\(S(n, k)\),表示将\(n\)个不同的元素划分为\(k\)个非空子集的方案数

\[{n \brace k}={n-1 \brace k-1}+{k}{n-1 \brace k} \]

即插入一个元素,可以:

  • 将元素单独放入一个集合
  • 将元素放入一个现有的集合
void initS2() {
    s[0][0] = 1;
    for (int i = 1; i <= 1000; ++ i)
        for (int j = 1; j <= 1000; ++ j)
            s[i][j] = (s[i - 1][j - 1] + j * s[i - 1][j] % mod) % mod;
}

int box5(int n, int k) {
    return s[n][k];
}

n个不相同的球,k个不相同的盒子,盒子可为空

ll qpow(ll a, ll b) {
    a %= mod;
    ll res = 1;
    while (b) {
        if (b & 1) res = (res * a) % mod;
        a = a * a % mod;
        b >>= 1;
    }
    return res;
}

int box6(int n, int k) {
    return qpow(k, n);
}

n个不相同的球,k个不相同的盒子,盒子不可为空

类似于\(n\)个不相同的球,\(k\)个相同的盒子,盒子不可为空,只不过此时盒子不相同

可以类比成将球先装入\(k\)个相同且不为空的袋子,再将袋子放入盒子,总的方案数为\({n \brace k} \times k!\)

void initFac() {
    fac[1] = 1;
    for (int i = 2; i <= 1000; ++ i) fac[i] = i * fac[i - 1] % mod;
}

int box7(int n, int k) {
    return s[n][k] * fac[n] % mod;
}

To Be Continue\(\dots \dots\)

posted @ 2023-07-25 10:04  Pan_ma_ru  阅读(143)  评论(0)    收藏  举报