要求:把n個(gè)骰子扔在地上,所有骰子朝上一面的點(diǎn)數(shù)之和為s。輸入n,打印出s的所有可能的值出現(xiàn)的概率。
思路:動(dòng)態(tài)規(guī)劃
1、n個(gè)骰子的點(diǎn)數(shù)和的最小值為n,最大值為6n;
2、n個(gè)骰子的所有點(diǎn)數(shù)的排列數(shù)為。
3、要解決這個(gè)問題,需要先統(tǒng)計(jì)出每個(gè)點(diǎn)數(shù)出現(xiàn)的次數(shù),然后把每個(gè)點(diǎn)數(shù)出現(xiàn)的次數(shù)除以,就能求出每個(gè)點(diǎn)數(shù)出現(xiàn)的概率;
4、 表示狀態(tài),設(shè)F(n,s)為當(dāng)骰子數(shù)為n,和為s的情況數(shù)量。
5、狀態(tài)轉(zhuǎn)移方程,使用 dp[n][j] 表示投完 n 枚骰子后總點(diǎn)數(shù)為 j 的出現(xiàn)次數(shù),那么我們考慮遞推關(guān)系式,投第 n 枚骰子可以由投第 n-1 枚骰子轉(zhuǎn)換而來,也就是如果投第 n-1 枚骰子后總點(diǎn)數(shù)為 j-i (1 ≤ i ≤ 6),那么第 n 次擲出 i 即可滿足條件。
當(dāng)n=1時(shí),F(xiàn)(1,s)=1,其中s=1,2,3,4,5,6
當(dāng)n≥2時(shí),F(xiàn)(n,s)=F(n?1,s?1)+F(n?1,s?2)+F(n?1,s?3)+F(n?1,s?4)+F(n?1,s?5)+F(n?1,s?6)
數(shù)學(xué)表達(dá)式為:
6、邊界處理,就是第一階段的狀態(tài):投擲完 11枚骰子后,它的可能點(diǎn)數(shù)分別為 1,2,3,...,6 ,并且每個(gè)點(diǎn)數(shù)出現(xiàn)的次數(shù)都是 1。
for (int i = 1; i <= 6; i ++) dp[1][i] = 1;
public double[] twoSum(int n) {
// +1是因?yàn)槠鋵?shí)從1開始,即丟骰子從第一次開始,沒有0
int dp[][]=new int[n+1][6*n+1];//表示i個(gè)骰子擲出s點(diǎn)的次數(shù)
for(int i=1;i<=6;i++) {
dp[1][i]=1;//表示一個(gè)骰子擲出i點(diǎn)的次數(shù)為1
}
for(int i=2;i<=n;i++) {//表示骰子的個(gè)數(shù)
for(int s=i;s<=6*i;s++) {//表示可能會(huì)出現(xiàn)的點(diǎn)數(shù)之和
for(int j=1;j<=6;j++) {//表示當(dāng)前這個(gè)骰子可能擲出的點(diǎn)數(shù)
if(s-j<i-1) {//當(dāng)總數(shù)還沒有j大時(shí),就不存在這種情況
break;
}
dp[i][s]+=dp[i-1][s-j];//當(dāng)前n個(gè)骰子出現(xiàn)的點(diǎn)數(shù)之和等于前一次出現(xiàn)的點(diǎn)數(shù)之和加上這一次出現(xiàn)的點(diǎn)數(shù)
}
}
}
double total = Math.pow((double)6,(double)n);//擲出n次點(diǎn)數(shù)出現(xiàn)的所有情況
double[] ans = new double[5*n+1];//因?yàn)樽畲缶椭粫?huì)出現(xiàn)5*n+1中點(diǎn)數(shù)
for(int i=n;i<=6*n;i++){
ans[i-n]=((double)dp[n][i])/total;//第i小的點(diǎn)數(shù)出現(xiàn)的概率
}
return ans;
}