[オファー] [60] [] Nのダイス

タイトル説明

  地面に投げn個のダイス、片側までのすべてのダイス及びS.ためのポイント数 nを入力し、sが発生するすべての可能な値の確率をプリントアウト。
  

ノー[牛質問アドレスネットワークをはねのけます]

アイデア解析

  1. 再帰的な方法。n及びダイスを決定するために、ダイスは、まず杭のn個に分割することができる:第一のスタックだけであり、他のパイルは、 N-1を有します。1〜6が表示される点の数を分離することができます。我々は、ポイントの数を計算する必要があり、残りのn-1個のサイコロの各1〜6ポイントと計算されます。:次に、残りのn-1は、依然として2つの山にダイスである第一のスタックが一つだけであり、第二のスタックは、 N-2番目を有しています。私たちは別々のサイコロの上にあることを入れて、このラウンドだけで合計をダイシングした後、残りのn-2サイコロのポイントを計算します。ここでの分析は、我々は、これは再帰的な思考であることがわかり、再帰終了条件は、最後だけサイコロということです。我々は、長さ6Nのアレイを画定するN + 1およびSNの配列の要素に点の数とsの出現数を節約することができます。
  2. あなたはこの問題を解決するためのアイデアを変更することができます。私たちは、表示されるサイコロの合計数を格納するために2回、各配列を考慮することができます。1サイクルでn個のデジタルの第1のアレイのnダイスの数を表し、出現しますループの次のパスは、新たな金型を追加し、この時点でNダイスの発生数は、一ダイスのサイクルとN-1に等しくなければならない、N-2、 N-3、N-4 数の和N-5、N-6、私たちは別の配列に対応するn番目の桁の前のn-1の配列を入れ、N-2、N-3 、N-4、N- 5とn-6デジタルサム。

テストケース

  1. 機能テスト:サイコロの各点の1,2,3,4確率。
  2. 特別な入力テスト:0を入力します。
  3. 性能試験:例えば11のような多数入ります。

Javaコード

public class Offer060 {
    public static void main(String[] args) {
        test1();
        test2();
        test3();
        
        

    }

    private static final int maxValue = 6;

    public static void printProbability1(int number) {
        Solution1(number);
    }

    /**
     * 方法一:递归解法
     */
    private static void Solution1(int number) {
        if (number <= 0)
            return; // 错误
        int[] probabilities = new int[maxValue * number - number + 1];
        // 下标为i,对应的值代表点数之和为i+number总共出现的情况次数
        // 点数从number~maxValue*number,所以数组大小为6*number-number+1
        for (int i = 0; i < probabilities.length; i++)
            probabilities[i] = 0;

        // 计算不同点数出现的次数
        for (int i = 1; i <= maxValue; i++)
            calP(probabilities, number, number - 1, i); // 第一次掷骰子,总点数只能是1~maxValue(即6)

        int totalP = (int) Math.pow(maxValue, number); // 所有情况总共出现的次数
        for (int i = 0; i < probabilities.length; i++) {
            double ratio = (double) probabilities[i] / totalP;
            NumberFormat format = NumberFormat.getPercentInstance();
            format.setMaximumFractionDigits(2);// 设置保留几位小数
            System.out.println("点数和为" + (i + number) + "的概率为:" + format.format(ratio));
        }
    }

    /**
     * 计算每种点数出现的次数
     * 
     * @param number:骰子总个数
     * @param curNumber:当前剩余骰子个数
     * @param sum:各个骰子加起来的总点数
     */
    private static void calP(int[] probabilities, int number, int curNumber, int sum) {
        if (curNumber == 0) {
            probabilities[sum - number]++; // 总数为sum的情况存放在sum-number下标中
            return;
        }
        for (int i = 1; i <= maxValue; i++)
            calP(probabilities, number, curNumber - 1, sum + i); // 相当于剩余的骰子少一个,总点数增加。
    }

/**
     * 方法二
     * @param number
     */
    private static void Solution2(int number) {
        if (number <= 0)
            return; // 错误
        int[][] probabilities = new int[2][number * maxValue + 1];
        // [2]代表用两个数组交替保存,[number*maxValue+1]是指点数为所在下标时,该点数出现的总次数。
        // probabilities[*][0]是没用的,只是为了让下标对应点数
//      for (int i = 0; i < 2; i++) {
//          for (int j = 0; j < number * maxValue; j++) {
//              probabilities[i][j] = 0;
//          }
//      }

        for (int i = 1; i <= 6; i++)
            probabilities[0][i] = 1; // 第一个骰子出现的情况

        int flag = 0;
        for (int curNumber = 2; curNumber <= number; curNumber++) { // 当前是第几个骰子
            for (int i = 0; i < curNumber; i++)
                probabilities[1 - flag][i] = 0; // 前面的数据清零

            for (int i = curNumber; i <= curNumber * maxValue; i++) {
                for (int j = 1; j <= 6 && j <= i; j++) {
                    probabilities[1 - flag][i] += probabilities[flag][i - j];
                }
            }
            flag = 1 - flag;

        }

        int totalP = (int) Math.pow(maxValue, number); // 所有情况总共出现的次数
        for (int i = number; i <= number * 6; i++) {
            double ratio = (double) probabilities[flag][i] / totalP;
            NumberFormat format = NumberFormat.getPercentInstance();
            format.setMaximumFractionDigits(8);// 设置保留几位小数
            System.out.println("点数和为" + (i + number) + "的概率为:" + format.format(ratio));
        }
    }

    private static void test1() {

    }

    private static void test2() {

    }

    private static void test3() {

    }

}

コードリンク

安全コードを証明するためにオファー-Java

おすすめ

転載: www.cnblogs.com/haoworld/p/offer60-n-ge-tou-zi-de-dian-shu.html