java - 如何计算使用N个六面骰子得到总和X的概率

标签 java algorithm time-complexity probability dice

挑战: 例如,使用 3 个六面骰子得到总和为 15 的概率是多少?例如,这可以通过获取 5-5-5 或 6-6-3 或 3-6-6 或更多选项来实现。

2 个骰子的强力解决方案 - 复杂度为 6^2:

假设我们只有 2 个六面骰子,我们可以编写这样的非常基本的代码:

public static void main(String[] args) {
   System.out.println(whatAreTheOdds(7));
}

public static double whatAreTheOdds(int wantedSum){
    if (wantedSum < 2 || wantedSum > 12){
        return 0;
    }

    int wantedFound = 0;
    int totalOptions = 36;

    for (int i = 1; i <= 6; i++) {
        for (int j = 1; j <= 6; j++) {
            int sum = i+j;
            if (sum == wantedSum){
                System.out.println("match: " + i  + " " + j );
                wantedFound +=1;
            }
        }
    }

    System.out.println("combinations count:" + wantedFound);
    return (double)wantedFound / totalOptions;
}

7 的输出将是:

match: 1 6

match: 2 5

match: 3 4

match: 4 3

match: 5 2

match: 6 1

combination count:6

0.16666666666666666

问题是如何推广算法以支持 N 个骰子:

public static double whatAreTheOdds(int wantedSum, int numberOfDices)

因为我们无法动态创建嵌套的 for 循环,所以我们必须采用不同的方法。

我想到了类似的事情:

 public static double whatAreTheOdds(int sum, int numberOfDices){

    int sum;
    for (int i = 0; i < numberOfDices; i++) {
        for (int j = 1; j <= 6; j++) {

        }
    }
}

但未能想出正确的算法。

这里的另一个挑战是 - 有没有一种方法可以有效地做到这一点,而不是复杂度为 6^N?

最佳答案

这是一个带有内存功能的递归解决方案来计算组合。

import java.util.Arrays;
import java.lang.Math;

class Dices {
    public static final int DICE_FACES = 6;

    public static void main(String[] args) {
        System.out.println(whatAreTheOdds(40, 10));
    }

    public static double whatAreTheOdds(int sum, int dices) {
        if (dices < 1 || sum < dices || sum > DICE_FACES * dices) return 0;

        long[][] mem = new long[dices][sum];
        for (long[] mi : mem) {
            Arrays.fill(mi, 0L);
        }
        long n = whatAreTheOddsRec(sum, dices, mem);
        return n / Math.pow(DICE_FACES, dices);
    }

    private static long whatAreTheOddsRec(int sum, int dices, long[][] mem) {
        if (dices <= 1) {
            return 1;
        }
        long n = 0;
        int dicesRem = dices - 1;
        int minFace = Math.max(sum - DICE_FACES * dicesRem, 1);
        int maxFace = Math.min(sum - dicesRem, DICE_FACES);
        for (int i = minFace; i <= maxFace; i++) {
            int sumRem = sum - i;
            long ni = mem[dicesRem][sumRem];
            if (ni <= 0) {
                ni = whatAreTheOddsRec(sumRem, dicesRem, mem);
                mem[dicesRem][sumRem] = ni;
            }
            n += ni;
        }
        return n;
    }
}

输出:

0.048464367913724195

编辑:郑重声明,该算法的复杂度仍然是 O(6^n),这个答案只是旨在为一般情况提供一个可能的实现,该实现比最简单的实现更好,使用记忆化和搜索空间修剪(仅探索可行的解决方案)。

关于java - 如何计算使用N个六面骰子得到总和X的概率,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60529498/

相关文章:

ruby-on-rails - 获取数组内元素的距离?

java - 如何将数学表达式树转换为简化形式?

java - 如何让类(class)持续运转

algorithm - 桶排序的近乎完美的分布模型

string - 删除字符串数组中重复项的最佳算法

c - 递归的大O

java - 选择特定字段不为 NULL 的所有记录

java - 断言语句后出现 ArrayIndexOutOfBoundsException

java - 对优先队列中的这一行感到困惑

python - 这个方程的时间复杂度是O(n)吗?