石子移动游戏:魔法操作

小明和小亮在玩一个石子游戏。
刚开始,小明有n堆石子,小亮有m堆石子。且两人每一堆石子所包含的石子个数均不超过6.
现在,小明需要执行d次魔法操作。每次魔法操作会从当前还剩余的几堆石子中随机选择一堆(选择每一堆的概率相同),并从这一堆中去掉一个石子。如果某一堆经过一次魔法操作后不再有任何石子,那么在下次魔法操作执行时则不会再考虑这一堆。
现在小明想知道,在经过d次魔法操作之后,小亮一堆石子都不剩的概率是多少?

【输入形式】
输入的第一行包含三个整数n,m和d(1 ≤n,m ≤ 5;1<=d<= 100).
接下来一行包含n个整数,表示小明每堆石子的初始石子数。
第三行包含m个整数,表示小亮每堆石子的初始石子数。所有石子数都在1到6之间(包括1和6)﹒

【输出形式】
输出经过d次魔法操作后,小亮一堆石子都不剩的概率。结果保留四位小数。

【样例输入】
1 2 2
2
1 1

【样例输出】
0.3333

  • 事件总数为N_event = A(N_ming+N_liang)/(小明每堆排列数乘积x小亮每堆排列数乘积)
  • 满足要求的数目N_right = A(N_liang)/(小亮每堆排列数乘积)xC(d-N_liang,N_ming)xA(N_ming)/(小明每堆排列数乘积)
  • 结果就是N_right/N_event=A(N_liang)A(N_ming)C(d-N_liang,N_ming)/A(N_ming+N_liang),对于样例就是2x2x1/12=0.33
    给个伪码
    N_ming,N_liang分别是两人的石子总数
    if N_liang>d, return 0
    else if N_ming+N_liang<=d return 1
    else{
    //return A(N_liang)A(N_liang)C(d-N_liang,N_ming)/A(N_ming+N_liang)
    }
    
    对于第3种情况,只能用程序遍历:
  • 可以构造多叉树,树节点存当前的每堆石子的概率,其实就是石子的堆数
  • 利用小亮的石子不能多于d-N_liang进行剪枝

给你参考


class Solution {
public:
    bool stoneGameIX(vector<int>& stones) {
        int s[3] = {0, 0, 0};
        for (int i : stones)         //相当于从stones中的值逐个取出给i
            ++s[i % 3];             //将石子价值按照模3余数分类计数
        if (s[0] % 2 == 0)          //模3余数是零的个数为偶数
            return s[1] != 0 && s[2] != 0;      //1和2的个数都不为0且Alice为先手
        return s[2] > s[1] + 2 || s[1] > s[2] + 2;      //可整除3的数为奇数个,所以次序可以颠倒,只有1和2的个数相差大于2时,取多的一个Alice才可以赢
    }
};