算法: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/

时间: 2024-10-23 14:42:58

算法:n个骰子的点数的相关文章

编程算法 - n个骰子的点数(递归) 代码(C)

n个骰子的点数(递归) 代码(C) 本文地址: http://blog.csdn.net/caroline_wendy 题目: 把n个骰子仍在地上, 所有骰子朝上一面的点数之和为s. 输入n, 打印出s的所有可能的值出现的概率. 采用递归的方法, 可以假设只有一个骰子, 然后骰子数递增相加. 代码: /* * main.cpp * * Created on: 2014.7.12 * Author: spike */ #include <stdio.h> #include <stdlib.

编程算法 - n个骰子的点数(非递归) 代码(C)

n个骰子的点数(非递归) 代码(C) 本文地址: http://blog.csdn.net/caroline_wendy 题目: 把n个骰子仍在地上, 所有骰子朝上一面的点数之和为s. 输入n, 打印出s的所有可能的值出现的概率. 每次骰子的循环过程中, 本次等于上一次n-1, n-2, n-3, n-4, n-5, n-6的次数的总和. 代码: /* * main.cpp * * Created on: 2014.7.12 * Author: spike */ #include <stdio.

模拟算法_掷骰子游戏&amp;&amp;猜数游戏

模拟算法是用随机函数来模拟自然界中发生的不可预测的情况,C语言中是用srand()和rand()函数来生成随机数. 先来介绍一下随机数的生成: 1.产生不定范围的随机数 函数原型:int rand() 产生一个介于0~RAD_MAX间的整数,其具体值与系统有关系.Linux下为2147483647.我们可以在include文件夹中的stdlib.h中可以看到(Linux在usr目录下,Windows在安装目录下) 1 #include<stdio.h> 2 #include<stdlib

《剑指offer》 面试题43 n个骰子的点数 (java)

引言:写这篇文章的初衷只是想做个笔记,因为这道题代码量有点大,有点抽象,而书上并没有详细的注释.为了加深印象和便于下次复习,做个记录. 原题:把n个骰子扔到地上,所有骰子朝上一面的点数之后为s. 输入n,打印出s所有可能的值出现的概率.(每个骰子6个面,点数从1到6) 解法一:基于递归,时间效率不高 递归的思想一般是分而治之,把n个骰子分为第一个和剩下的n-1个.先计算第一个骰子每个点数出现的次数,再计算剩余n-1个骰子出现的点数之和.求n-1个骰子的点数之的方法和前面讲的一样,即再次把n-1个

【编程题目】n 个骰子的点数

67.俩个闲玩娱乐(运算).2.n 个骰子的点数.把 n 个骰子扔在地上,所有骰子朝上一面的点数之和为 S.输入 n,打印出 S 的所有可能的值出现的概率. 思路:用递归把每个骰子的可能情况变量,记录各种和S出现的次数 比上 总情况数就是概率 /* 67.俩个闲玩娱乐(运算). 2.n 个骰子的点数. 把 n 个骰子扔在地上,所有骰子朝上一面的点数之和为 S.输入 n, 打印出 S 的所有可能的值出现的概率. */ #include <stdio.h> #include <stdlib.

n个骰子的点数

题目:把n个骰子扔在地上,所有骰子朝上一面的点数之和为s,输入n,打印出s的所有可能的值出现的概率. 解法一:基于递归求骰子点数,时间效率不高. 现在我们考虑如何统计每一个点数出现的次数.要想求出n个骰子的点数和,可以先把n个骰子分为两堆:第一堆只有一个,另一个有n-1个,单独的那一个有可能出现从1到6的点数.我们需要计算从1到6的每一种点数和剩下的n-1个骰子来计算点数和.接下来把剩下的n-1个骰子还是分成两堆,第一堆只有一个,第二堆有n-2个.我们把上一轮那个单独骰子的点数和这一轮单独筛子的

剑指Offer面试题43(Java版):n个骰子的点数

题目:把n个骰子仍在地上.全部骰子朝上一面的点数之和为s,输入n,打印出s的全部可能的值出现的概率. 解法一:基于递归求骰子的点数,时间效率不够高 如今我们考虑怎样统计每个点数出现的次数. 要向求出n个骰子的点数和.能够先把n个骰子分为两堆:第一堆仅仅有一个.还有一个有n-1个.单独的那一个有可能出现从1到6的点数. 我们须要计算从1到6的每一种点数和剩下的n-1个骰子来计算点数和. 接下来把剩下的n-1个骰子还是分成两堆,第一堆仅仅有一个.第二堆有n-2个. 我们把上一轮哪个单独骰子的点数和这

n个骰子各点数和出现的概率--动态规划

题目:把n个骰子扔在地上,所有骰子朝上一面的点数之和为S.输入n,打印出S的所有可能的值出现的概率. 声明思想非原创!只因动态规划思想的使用很好,记下! 分析:动态规划就是分阶段考虑问题,给出变量,找出相邻阶段间的关系.具体定义给忘了. 1.现在变量有:骰子个数,点数和.当有k个骰子,点数和为n时,出现次数记为f(k,n).那与k-1个骰子阶段之间的关系是怎样的? 2.当我有k-1个骰子时,再增加一个骰子,这个骰子的点数只可能为1.2.3.4.5或6.那k个骰子得到点数和为n的情况有: (k-1

剑指offer (43) n个骰子的点数

题目:把n个骰子扔在地上,所有骰子朝上一面的点数之和为s,输入n,打印出s的所有可能的值出现的概率 int g_maxValue = 6; // ====================方法一==================== void Probability(int number, int* pProbabilities); void Probability(int original, int current, int sum, int* pProbabilities); void Pr

n 个骰子的点数

题目 把 n 个骰子扔在地上,所有骰子朝上一面的点数之和为 s.输入 n,打印出 s 的所有可能的值出现的概率. 思路 解法一: 先把 n 个骰子分为两堆:第一堆只有一个,另一个有 n-1 个.单独的那一个有可能出现从 1 到 6 的点数.我们需要计算从 1 到 6 的每一种点数和剩下的 n-1 个骰子来计算点数和.接下来把剩下的 n-1 个骰子还是分成两堆,第一堆只有一个, 第二堆有 n-2 个.我们把上一轮那个单独骰子的点数和这一轮单独骰子的点数相加, 再和剩下的 n-2 个骰子来计算点数和