質問とテスト
package sword043;
/* 题目:把n个骰子仍在地上,所有骰子朝上一面的点数之和为s,输入n,打印出s的所有可能的值出现的概率。
*/
import java.util.List;
public class main {
public static void main(String[] args) {
int [] testTable = {0,6,3};
for (int ito : testTable) {
test(ito);
}
}
private static void test(int ito) {
Solution solution = new Solution();
long begin = System.currentTimeMillis();
System.out.print(ito);
System.out.println();
//开始时打印数组
solution.printProbability(ito);//执行程序
long end = System.currentTimeMillis();
System.out.println();
System.out.println("耗时:" + (end - begin) + "ms");
System.out.println("-------------------");
}
}
解決策1:サイコロの数を見つけるための再帰に基づいて、時間効率が十分に高くない
ここで、各ポイントの発生数をカウントする方法を検討します。n個のサイコロのポイントの合計を見つけるには、最初にn個のサイコロを2つの山に分割します。最初の山には1つだけがあり、もう1つの山にはn-1があります。単一のものは1から6までのポイントを持つことができます。ポイントの合計を計算するには、1から6までのポイント数と残りのn-1個のサイコロを計算する必要があります。次に、残りのn-1個のサイコロを2つのサイコロに分割します。最初のサイコロは1つだけで、2番目のサイコロはn-2です。前のラウンドの個々のサイコロの数をこのラウンドの個々のサイコロの数に加算し、次にn-2個のサイコロを加算してポイントの合計を計算します。分析のこの時点で、これが再帰的なアイデアであることがわかるのは難しくありません。再帰が終了するための条件は、ダイが1つだけ残っていることです。
解決策2:ループに基づいてサイコロの数を見つけ、優れた時間パフォーマンスを実現します
この問題を別の方法で解決するために、2つの配列を使用して、サイコロポイントの各要約の発生数を格納することを検討できます。ループでは、各配列のn番目の数値は、サイコロの合計がnである回数を表します。ループの次のラウンドでは、新しいサイコロを追加します。合計はnの出現回数です。次のラウンドでは、新しいサイコロを追加します。この時点で、合計nのサイコロの出現数は、前のサイクルのサイコロポイントの数と等しくなり、合計はn-1、n-になります。 2、n-3、n-4、n -5の時間の合計なので、別の配列のn番目の数をn-1、n-2、n-3、n-4、n-5に設定します。前の配列に対応
public class Solution {
public void printProbability(int n) {
if(n<=0) {
return;
}
int total = 6 * n;
int[] arrayNow = new int[total + 1];
int[] arrayNext = new int[total + 1];
for(int i=1;i<7;i++) {
arrayNow[i] = 1;
}
for(int k = 2;k<=n;k++) {
for(int i=1;i<=6*k-6;i++) {
for(int j=1;j<=6;j++) {
arrayNext[i+j] += arrayNow[i];
}
}
arrayNow = arrayNext;
arrayNext = new int[total + 1];
}
double totalProbability = Math.pow(6, n);
for(int i=1;i<=6*n;i++) {
double ratio = (double)arrayNow[i]/totalProbability;
System.out.println(i+" "+ratio);
}
}
}