面试题 43,n个骰子的点数

这道题要用递推的思想做。
假设骰子是最常见的骰子,有6个面,1-6
对于n个骰子,其和的可能性有n到6n这么多种情况。
(1) 假设f(m) 表示骰子数目为n时,和为m的可能性的数量,当骰子数量从n变为n+1,由于组合更多,之前计算好的和为m的可能性的数量也会变化。
考虑到新的骰子可以从1变到6,要想让所有骰子和依然为m,那么其余的骰子的和就需要从m-6变到m-1,也就是说对于 m <= 6n,得出公式1: f(m) = f(m-6) + f(m-5) + ... + f(m-1)
(2) 第n+1颗骰子的加入会让和的上限从原来的 6n变为 6(n+1),那么这多出来的6个值:f(6n+1)到f(6n+6) 怎么计算?
以f(6n+1)为例,我们依然考虑新骰子可以从1变到6,其余的n个骰子的和就需要从6n变到6n-5,因此f(6n+1)依然可以用上面的公式做。
对于f(6n+2)呢?新骰子可以从1变到6,其余的n个骰子的和就需要从6n+1变到6n-4,而n个骰子是不可能和为6n+1的,所以f(6n+2) = f(6n) + ... + f(6n-4),和上面的公式1相比,少了f(m-1),但是如果我们用数组表示的话,我们可以假设所有初值为0,这样当我们计算出f(6n)以及之前的所有值的时候,f(6n+1)仍然为0,因此 f(6n+2) = f(6n+1) + f(6n) +... + f(6n-4)依然成立。
所以,f(m) = f(m-6) + f(m-5) + ... + f(m-1)。
我们用数组来实现,需要注意的是,我们必须用两组数组来做,一个数组表示n个骰子情况下所有和的情况,然后计算出n+1情况下各种和的值存到另一个数组中。两个数组相互用。
可以用m&1表示当前要计算的数组,1-m&1表示另一个数组。
我自己的代码,没有经过严格检验。
#include <stdio.h> double* CalcuSumRatio(int num, const int MaxValue){ if(num <= 0) return NULL; int** sum = new int*[2]; int i = 0, j = 0, k = 0; for(i = 0; i < 2; i++){ sum[i] = new int[MaxValue * num + 1]; for(j = 0;j < MaxValue * num + 1; j++) sum[i][j] = 0; } for(k = 1; k <= MaxValue; k++) sum[1][k] = 1; for(i = 2; i <= num; i++){ //printf("Round %d:---------------\n", i); for(j = 0; j < i; j++) sum[i & 1][j] = 0; for(j = i; j <= MaxValue * i; j++){ sum[i & 1][j] = 0; for(k = 1; k <= MaxValue; k++){ if((j-k) > 0){ sum[i & 1][j] += sum[1 - i&1][j - k]; } } //printf("%d: %d\n", j, sum[i & 1][j]); } } double* Radio = new double[MaxValue * num + 1]; long long totalSumNum = 0; for(i = num; i < MaxValue * num + 1; i++) totalSumNum += sum[num&1][i]; for(i = 0; i < num; i++) Radio[i] = 0; for(i = num; i < MaxValue * num + 1; i++){ Radio[i] = (sum[num&1][i] * 1.0)/totalSumNum; printf("%d: %e\n", i, Radio[i]); } return Radio; } int g_maxValue = 6; // ====================测试代码==================== void Test(int n) { printf("Test for %d begins:\n", n); double* ratio = CalcuSumRatio(n, g_maxValue); printf("\n"); } int main() { Test(1); Test(2); Test(3); Test(4); Test(11); Test(0); return 0; }
其实这道题用递归做更加直观,但是效率比上面的循环实现就要低了。
书上代码:
void PrintProbability_Solution2(int number) { if(number < 1) return; int* pProbabilities[2]; pProbabilities[0] = new int[g_maxValue * number + 1]; pProbabilities[1] = new int[g_maxValue * number + 1]; for(int i = 0; i < g_maxValue * number + 1; ++i) { pProbabilities[0][i] = 0; pProbabilities[1][i] = 0; } 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]; }
------------------------------------------------
Felix原创,转载请注明出处,感谢博客园!
posted on 2014-03-09 01:28 Felix Fang 阅读(313) 评论(0) 收藏 举报
浙公网安备 33010602011771号