• n个骰子的点数


     题目:把n个骰子扔在地上,所有骰子朝上一面的点数之和为s,输入n,打印出s的所有可能的值出现的概率。
    解法一:基于递归求骰子点数,时间效率不高。
     现在我们考虑如何统计每一个点数出现的次数.要想求出n个骰子的点数和,可以先把n个骰子分为两堆:第一堆只有一个,另一个有n-1个,单独的那一个有可能出现从1到6的点数.我们需要计算从1到6的每一种点数和剩下的n-1个骰子来计算点数和.接下来把剩下的n-1个骰子还是分成两堆,第一堆只有一个,第二堆有n-2个。我们把上一轮那个单独骰子的点数和这一轮单独筛子的点数相加,再和剩下的n-2个骰子来计算点数和。递归结束的条件就是最后只剩下一个骰子。
    基于这种思路,代码参考如下:
     1 int g_maxValue=6;
     2 void PrintProbability(int number)
     3 {
     4   if(number<1)
     5   return;
     6   int maxSum=num*g_maxValue;
     7   int* pProbabilities=new int[maxSum-number+1];
     8   for(int i=number;i<=maxSum;++i)
     9   pProbabilities[i-number]=0;
    10   Probability(number,pProbabilities);
    11   int total=pow((double)g_maxValue,number);
    12   for(int i=number;i<=maxSum;++i)
    13   {
    14    double ratio=(double)pProbabilities[i-number]/total;
    15    printf("%d:%e
    ",i,ratio);
    16   }
    17   delete []probabilities;
    18  }
    19 
    20 void Probability(int number,int* pProbabilities)
    21 {
    22  for(int i=1;i<=g_maxValue;++i)
    23  Probability(number,number,i,pProbabilities);
    24  }
    25 
    26 void Probability(int original,int current,int sum,int* pProbabilities)
    27 {
    28   if(current==1)
    29   { pProbabilities[sum-original]++; }
    30  else
    31    {
    32    for(int i=1;i<=g_maxValue;++i)
    33     {Probabilitiey(original,current-1,i+sum,pProbabilities);}
    34    }
    35  }

    上述思路很简洁,实现起来很容易。但由于是基于递归实现,它有很多的计算是重复的,从而导致当number变大时性能慢得让人不能接受.

    解法二:基于循环求骰子点数,时间性能好
    可以换一种思路来解决这个问题。我们可以考虑用两个数组来存储骰子的每一个总数出现的次数。在一次循环中,第一个数组中的第n个数字表示骰子和为n出现的次数.在下一次循环中,我们加上一个新的骰子,此时和为n的骰子出现的次数应该等于上一次循环中骰子点数和为n-1,n-2,n-3,n-4,n-5与n-6的次数的总和,所以我们把另一个数组的第n个数字设为前一个数组对应的第n-1,n-2,n-3,n-4,n-5与n-6之和。基于这个思路,参考代码如下:
     1 int g_maxValue=6;
     2 void PrintProbability(int number)
     3 {
     4  if(number<1) return;
     5  int *pProbabilities[2];
     6  pProbabilities[0]= new int[g_maxValue*number+1];
     7  pProbabilities[1]=new int[g_maxValue*number+1];
     8  for(int i=0;i<g_maxValue*number+1;++i)
     9  {
    10   pProbabilities[0][i]=0;
    11   pProbabilities[1][i]=0;
    12  }
    13 
    14  int flag=0;
    15  for(int i=1;i<=g_maxValue;++i)
    16   pProbabilities[flag][i]=1;
    17 
    18  for(int k=2;k<=number;++k)
    19  {
    20    for(int i=0;i<k;++i)
    21     pProbabilities[1-flag][i]=0; 
    22    
    23     for(int i=k;i<=g_maxValue*k;++i)
    24   {
    25     pProbabilities[1-flag][i]=0;
    26     for(int j=1;j<=i&&j<=g_maxValue;++j)
    27      pProbabilities[1-flag][i] +=pProbabilities[flag][i-j];
    28   }
    29  flag=1-flag;
    30  }
    31 
    32 double total=pow((double)g_maxValue,number);
    33   for(int i=number;i<=g_maxValue*number;++i)
    34   {
    35    double ratio=(double)pProbabilities[flag][i]/total;
    36    printf("%d:%e
    ",i,ratio);
    37   }
    38 delete []pProbabilities[0];
    39 delete []pProbabilities[1];
    40 }
    在上述代码中,我们定义了两个数组pProbabilities[0]和pProbabilities[1]来存储骰子的点数之和。在一轮循环中,一个数组的第n项等于另一个数组的第n-1,n-2,n-3,n-4,n-5,n-6项的和。在下一轮循环中,我们交换这两个数组(通过改变变量flag实现)再重复这一计算过程。
    值得注意的是,上述代码没有在函数里把一个骰子的最大点数硬编码为6,而是用一个变量g_maxValue来表示。这样做的好处是如果某个厂家生产了其他点数的骰子,我们只需要在代码中修改一个地方,扩展起来很方便。
  • 相关阅读:
    设计模式
    Junit单元测试
    数组存储和链表存储
    java新特型
    List&&Set
    Map
    File文件
    1588. 所有奇数长度子数组的和
    2秒后跳转到某页面
    图片轮播/倒计时--windows对象(setInterval)
  • 原文地址:https://www.cnblogs.com/wxdjss/p/5559424.html
Copyright © 2020-2023  润新知