Dices Sum(骰子求和)

完成题目和写完报告共花费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] = 1result= (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*nfor (int k = 1; k <= 6; ++k){//k:每多掷一个骰子的情况,一个骰子只能掷到1~6if (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;

}

如果作者写的对你们有帮助的话,就点个赞吧!

猜你喜欢

转载自blog.csdn.net/huyr_123/article/details/81590292
今日推荐