算法:n个骰子的点数

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

 一般来说骰子点数为1~6,n个筛子的点数之和可以这样理解:第n个骰子可能出现的数与前面(n-1)个骰子和的和,前面(n-1个骰子)的和为第(n-1)个骰子可能出现的数与前面(n-2)个骰子和的和。。以此类推。以动态规划的方式求解。

1.用递归解决

建立一个长度[n*g_maxValue]的表,a[n]表示和为n出现的次数,除以6^n即为概率。

#include <stdio.h>
#include <iostream>
#include <time.h>
using namespace std;
int g_maxValue = 6;//定义骰子最大值

 

void getnum2(int n,int sum,int a[])
{
if(n==0)

{
a[sum]++;
return;
}
for(int i=1;i<=g_maxValue;i++)
{int temp=sum+i;

getnum2(n-1,temp,a);//6个分支  每一个去求前面n个骰子的和,时间复杂度6的指数级递增
}
}

void main()
{
time_t tstart=time(NULL); //获取当前时间
int n=12;
getnum(n);
time_t tend=time(NULL);/获取递归结束后时间
cout<<endl;
cout<<tend-tstart;//打印递归时间
}

2.用数组的方法解决

每增加一个骰子,即在原来的基础上增加了1~6,即和为n的数为(n-1)~(n-6)出现次数之和。

用两个数组表示n-1个骰子的情况和n个骰子的情况。

#include <stdio.h>
#include <iostream>
#include <time.h>
using namespace std;
int g_maxValue = 6;
void getnum(int n)
{
int *allnum[2];
allnum[0]=new int[n*g_maxValue+1];
allnum[1]=new int[n*g_maxValue+1];
for(int i=0;i<=n*g_maxValue;i++)
{
allnum[0][i]=0;
allnum[1][i]=0;
}
int flag=0;
for(int i=1;i<=g_maxValue;i++)
allnum[flag][i] = 1;
for(int k=2;k<=n;k++)
{
for(int i=k*g_maxValue;i>=k;i--)
{
allnum[1-flag][i]=0;

for(int j=1;j<=i&&j<=g_maxValue;j++)
{
allnum[1-flag][i]=allnum[1-flag][i]+allnum[flag][i-j];
}

}
for(int i=0;i<n*g_maxValue;i++)
allnum[flag][i]=0;
flag=1-flag;
}
for(int i=n;i<=n*g_maxValue;i++)
{
if(allnum[0][n]!=0)
cout<<allnum[0][i]<<" ";
else cout<<allnum[1][i]<<" ";
}
delete [] allnum[0];
delete [] allnum[1];

}


void main()
{
time_t tstart=time(NULL);
int n=12;
getnum(n);
time_t tend=time(NULL);;
cout<<endl;
cout<<tend-tstart;
}

 

方法时间差距很大,在n=12的时候,VS递归的要66s,DP的用0s。

3.在参考的博客评论里还有个更粗暴的

void dice1()
{
 const int n = 6;
 int sum[n * n + 1] = {0};

 for(int i = 1; i <= n; i++)
 {
  for(int j = 1; j <= n; j++)
  {
   for(int k = 1; k <= n; k++)
   {
    for(int x = 1; x <= n; x++)
    {
     for(int y = 1; y <= n; y++)
     {
      for(int z = 1; z <= n; z++)
      {
       sum[i + j + k + x + y + z]++;
      }
     }
    }
   }
  }
 }
}

详情参考:http://zhedahht.blog.163.com/blog/static/254111742009101524946359/

转载于:https://www.cnblogs.com/gardener/p/5985496.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值