完成题目和写完报告共花费2h12分钟。
题目链接:https://www.lintcode.com/problem/dices-sum/description
题目:扔 n 个骰子,向上面的数字之和为 S。给定 Given n,请列出所有可能的 S 值及其相应的概率。
给定 n = 1,返回 [ [1, 0.17], [2, 0.17], [3, 0.17], [4, 0.17], [5, 0.17], [6, 0.17]]
当n=1时,即掷1个骰子时,掷到1~6的次数都可能为1次,概率都为1/6.
由上表可以看出,
当n=2时,即掷2个骰子,掷到的数的概率如下
P(2)=1/36 p(8)=5/36
P(3)=2/36 p(9)=4/36
P(4)=3/36 p(10)=3/36
P(5)=4/36 p(11)=2/36
P(6)=5/36 p(12)=1/36
p(7)=6/36
用T[i][j]表示在掷i+1个骰子的情况下,掷到的和为j的次数。
初始化:当掷1个骰子时,则T[0][j],j=1~6的次数为1,T[0][j]=1,每个数的概率就用该次数除以6,即掷到每个数的概率为1/6。
初始化代码(初始化不如将T[1][j]表示为掷1个骰子时,掷到每个数的次数,result(类型double)表示掷到每个数的概率):
a[i][j]={0};
for (int i = 1; i <= 6; ++i)
a[1][i] = 1。
result= (1.0)*a[1][i]/6。
此时a[i][j]表示掷i个骰子,掷到和为j的次数。
for (int i = 2; i <= n; ++i){ //i:表示掷了几个骰子
for (int j = i; j <= 6 * n; ++j) {//j:当掷n个骰子时,掷到的数的范围为n~6*n。
for (int k = 1; k <= 6; ++k){//k:每多掷一个骰子的情况,一个骰子只能掷到1~6点
if (j > k)//因为不可能掷到0点,所以j必须大于k
a[i][j] = a[i][j]+ a[i - 1][j - k];
}
}
}
result= (1.0)*a[i][j]/ (6^n);
掷1个骰子和掷2个骰子的区别:主要多掷了一个骰子。
依次类推:掷i个骰子和i+1个骰子的区别也是多掷了一个骰子。
1个骰子的掷到j(j=1….6)的次数都可能为1次,每个数的概率为T[1][j]=1。
每多掷一个骰子,就需要再用一个k = 1…6进行遍历。
2个骰子的掷到j+k的次数就是(其中j>k)
for (int j = 2; j <= 6 * n; ++j) {
for (int k = 1; k <= 6; ++k){//k:每多掷一个骰子的情况,一个骰子只能掷到1~6点
if (j > k)//因为不可能掷到0点,所以j必须大于k
a[2][j] += a[1][j - k];
}
}
根据这个得数就可以得到:a[2][2]=a[1][1]=1,a[2][3]=2,a[2][4]=3,a[2][5]=4,a[2][6]=5,a[2][7]=6,a[2][8]=5, a[2][9]=4, a[2][10]=3, a[2][11]=2, a[2][12]=1。
最后得到的规律:T [i][j] = T[i][j]+ T[i - 1][j - k];
JAVA代码:
public class Solution {
/**
* @param n an integer
* @return a list of Map.Entry<sum, probability>
*/
public List<Map.Entry<Integer, Double>> dicesSum(int n) {
// Write your code here
// Ps. new AbstractMap.SimpleEntry<Integer, Double>(sum, pro)
// to create the pair.
List<Map.Entry<Integer, Double>> results =
new ArrayList<Map.Entry<Integer, Double>>();
double[][] a= new double[n + 1][6 * n + 1];
for (int i = 1; i <= 6; ++i)
a[1][i] = 1.0 / 6;
for (int i = 2; i <= n; ++i)
for (int j = i; j <= 6 * n; ++j) {
for (int k = 1; k <= 6; ++k)
if (j > k)
a[i][j] += a[i - 1][j - k];
a[i][j] /= 6.0;
}
for (int i = n; i <= 6 * n; ++i)
results.add(new AbstractMap.SimpleEntry<Integer, Double>(i, a[n][i]));
return results;
}
}
C++语言:
#include<iostream>
#include<cmath>
#include<string.h>
using namespace std;
int main(){
int n;
while(cin>>n){
int a[100][1000];//a[i][j]表示掷i个骰子,掷到j的次数。
memset(a,0,sizeof(a));
double result[100];
if(n==1){
for(int i=1;i<=6;i++)
printf("%d %.2lf\n",i,1.0/6);
}else{
for(int i=1;i<=6;i++){
a[1][i]=1;
result[i]=1.0/6;
}
//a[2][2]=0;
for(int i=2;i<=n;i++){
for(int j=i;j<=6*n;j++){
for(int k=1;k<=6;k++){
if(j>k){
//printf("test1:%d %d\n",j,a[i][j]);
a[i][j]=a[i][j]+a[i-1][j-k];
//printf("test2:%d %d\n",j,a[i][j]);
}
}
//a[i][j]有错
//printf("%d\n",a[i][j]);
result[j]=1.0*a[i][j]/(pow(6,n));
}
}
for(int j=n;j<=6*n;j++)
printf("%d %.2lf\n",j,result[j]);
}
}
return 0;
}
如果作者写的对你们有帮助的话,就点个赞吧!