您的位置:首页 > Web前端

剑指Offer-60:n个骰子的点数

2018-03-27 15:01 337 查看

题目:

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

链接:

剑指Offer(第2版):P294

思路标签:

算法:递归动态规划

解答:

1. 基于递归的方法,效率低

我们将大问题n个骰子的点数和,转化为求第1个和后面n-1个骰子;

同时用一个数组来保存所有可能和出现的次数,注意是和出现的次数,即每次该和出现一次,对应的位置上就+1;

利用递归去求解,每一个骰子都有6种可能性,排列组合总共有6^n种可能;

结束条件是每次得到最后一个骰子的结果;

最后求概率注意int和double的转换。

class Solution {
public:
void PrintProbility(int number) {
if (number < 1)
return;

int maxSum = number * g_maxValue;
int * pProbabilities = new int[maxSum - number + 1];
for (int i = number; i <= maxSum; ++i)
pProbabilities[i - number] = 0;

Probability(number, pProbabilities);

int total = pow((double)(g_maxValue), number);
for (int i = number; i <= maxSum; ++i) {
double ratio = (double)pProbabilities[i - number] / total;
printf("%d: %e\n", i, ratio);
}
}

void Probability(int number, int* pProbabilities) {
for (int i = 1; i <= g_maxValue; ++i)
Probability(number, number, i, pProbabilities);
}

void Probability(int original, int current, int sum, int* pProbabilities) {
if (current == 1)
pProbabilities[sum - original]++;
else {
for (int i = 1; i <= g_maxValue; ++i)
Probability(original, current - 1, i + sum, pProbabilities);
}
}

private:
int g_maxValue = 6;

};


2. 基于循环求骰子点数,性能较好(动态规划)

使用动态规划的思想其时间复杂度总是要小于递归的方法;

我们设立数组,用数组中的第n个数表示骰子点数和为n的次数;

第k次投掷骰子的数可能为1~6中的任意一个数,如果我们假设第k次投掷骰子最终所有的和为n,那么和为n的次数就为前一次投掷(第k-1次投掷)和为n-1、n-2、n-3、n-4、n-5、n-6的次数的总和。

同时知道第1次投掷和为1,2,3,4,5,6的次数均为1;同时第k次投掷时,和为0、1、2…k-1将不会存在;

我们使用两个数组来交替进行,一个用来保存上一次投掷的和的次数,另一个以对方为基础用来计算当前投掷和的次数。每次用flag来交替。

class Solution {
public:
void PrintProbility(int number) {
if (number < 1)
return;

int* pProbabilities[2];
int length = g_maxValue*number + 1;
pProbabilities[0] = new int[length];
pProbabilities[1] = new int[length];
for (int i = 0; i < length; ++i) {
pProbabilities[0][i] = 0;
pProbabilities[1][i] = 1;
}

int flag = 0;

for (int i = 1; i <= g_maxValue; ++i)
pProbabilities[flag][i] = 1;

for (int k = 2; k <= number; ++k) {
for (int i = 0; i < k; ++i)
pProbabilities[1 - flag][i] = 0;

for (int i = k; i <= g_maxValue*k; ++i) {
pProbabilities[1 - flag][i] = 0;
for (int j = 1; j <= i && j <= g_maxValue; ++j)
pProbabilities[1 - flag][i] += pProbabilities[flag][i - j];
}

flag = 1 - flag;
}

double total = pow((double)g_maxValue, number);
for (int i = number; i <= g_maxValue*number; ++i) {
double ratio = (double)pProbabilities[flag][i] / total;
printf("%d: %e\n", i, ratio);
}

delete[] pProbabilities[0];
delete[] pProbabilities[1];
}

private:
int g_maxValue = 6;
};
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息