zoukankan      html  css  js  c++  java
  • n 个骰子的点数

    题目

      把 n 个骰子扔在地上,所有骰子朝上一面的点数之和为 s。输入 n,打印出 s 的所有可能的值出现的概率。

    思路

    解法一:

      先把 n 个骰子分为两堆:第一堆只有一个,另一个有 n-1 个。单独的那一个有可能出现从 1 到 6 的点数。我们需要计算从 1 到 6 的每一种点数和剩下的 n-1 个骰子来计算点数和。接下来把剩下的 n-1 个骰子还是分成两堆,第一堆只有一个, 第二堆有 n-2 个。我们把上一轮那个单独骰子的点数和这一轮单独骰子的点数相加, 再和剩下的 n-2 个骰子来计算点数和。分析到这里,我们不难发现这是一种递归的思路,递归结束的条件就是最后只剩下一个骰子。

    我们可以定义一个长度为“6n-n+1”的数组, 和为 s 的点数出现的次数保存到数组第 s-n 个元素里。

    解法二:

      1.现在变量有:骰子个数,点数和。当有c个骰子,点数和为k时,出现次数记为dp(c,k)。
      2.当我有c-1个骰子时,再增加一个骰子,这个骰子的点数只可能为1、2、3、4、5或6。那k个骰子得到点数和为n的情况有:

      (c-1,k-1):第c个骰子投了点数1

      (c-1,k-2):第c个骰子投了点数2

      (c-1,k-3):第c个骰子投了点数3

       ....

      (c-1,k-6):第c个骰子投了点数6

      在c-1个骰子的基础上,再增加一个骰子出现点数和为k的结果只有这6种情况!所以:dp(c,k)=dp(c-1,k-1)+dp(c-1,k-2)+dp(c-1,k-3)+dp(c-1,k-4)+dp(c-1,k-5)+dp(c-1,k-6)(注意当k<6时的处理越界问题) 

      3.有1个骰子,dp(1,1)=dp(1,2)=dp(1,3)=dp(1,4)=dp(1,5)=dp(1,6)=1。

    因此状态转移方程为

    dp[c][k]=sum(dp[c-1][k-m])(1<=m<=6&&m<k)
    #include <iostream>
    #include <cmath>
    using namespace std;
    
    const int max_value=6;//单个骰子的最大值 
    
    class Solution
    {
        public:
            void probality(int n);//递归 
            void probality(int original,int index,int curr_sum,int *value);
            void cricile_probality(int n);//基于循环解法 
    };
    void Solution::probality(int n)
    {
        if(n<1)
            return;
        
        int max_sum=n*max_value;//n个骰子的最大值 
        int *value=new int[max_sum-n+1];//定义6*n-n+1的数组
        for(int i=n;i<=max_sum;++i)
            value[i-n]=0;//将和为s的点数存放到数组的第s-n个元素里
        
        int curr_sum=0;
        probality(n,n,curr_sum,value); 
        
        int sum=pow((double)max_value,n);
        for(int i=n;i<=max_sum;++i)
        {
            double ratio=(double)value[i-n]/sum;
            cout<<i<<' '<<ratio<<endl;
        }
        
        delete []value;
        return;
    }
    void Solution::probality(int original,int index,int curr_sum,int *value)
    {
        if(index==0)
        {
            value[curr_sum-original]+=1;
            return;
        }
        for(int i=1;i<=max_value;++i)
            probality(original,index-1,i+curr_sum,value);
    }
    void Solution::cricile_probality(int n)
    {
        if(n<1)
            return;
        int *value[2];
        value[0]=new int[max_value*n+1]; 
        value[1]=new int[max_value*n+1];
        for(int i=0;i<max_value*n+1;++i)
        {
            value[0][i]=0;
            value[1][i]=1;
        }
        
        int flag=0;//标记当前使用的是0数组还是1数组
        for(int i=1;i<=max_value;++i)//第一次投骰子 
            value[flag][i]=1; 
        
        //抛出其他骰子
        for(int k=2;k<=n;++k)
        {
            for(int i=0;i<k;++i)//如果抛出了k个骰子,那么和为[0, k-1]的出现次数为0
                value[1-flag][i]=0;
            
            for(int i=k;i<=max_value*k;++i)//抛出k个骰子,所有和的可能
            {
                value[1-flag][i]=0;
                for(int j=1;j<=i&&j<=max_value;++j)
                    value[1-flag][i]+=value[flag][i-j];
            }
            flag=1-flag;
        }
        int sum=pow((double)max_value,n);
        for(int i=n;i<=max_value*n;++i)
        {
            double ratio=(double)value[flag][i]/sum;
            cout<<i<<' '<<ratio<<endl;
        }
        
        for(int i=0;i<max_value*n+1;++i)
        {
            delete []value[0];
            delete []value[1];
        }
        return;
    }
    int main()
    {
        Solution s;
        s.probality(6);
        s.cricile_probality(6);
        return 0;
    }
  • 相关阅读:
    Git工作中用法(Gitlab)
    面试记录,不定时更新中。。。
    webservice 技术改进
    HTTP详解
    Git学习05 --分支管理02
    Git学习04 --分支管理
    链表判环问题
    k-选取问题
    图片与字符串(base64编码)的转化
    二叉堆与堆排序的简单实现
  • 原文地址:https://www.cnblogs.com/tianzeng/p/10308858.html
Copyright © 2011-2022 走看看