【面試題043】n個骰子的點數
題目:
把n個骰子扔在地上,所有骰子朝上一面的點數之和為s,
輸入n,打印出s的所有可能的值出現的概率。
n個骰子的總點數,最小為n,最大為6n,根據排列組合的知識,那個骰子,所有點數的排列數為6^n。
我們先統計每一個點數出現的次數,然后把每一個點數出現的次數除以6^n,就能求出每個點數出現的概率。
思路一:
基於遞歸求骰子點數,時間效率不夠高。
- 先把骰子分成兩堆,第一堆只有一個,第二堆有n-1個,
- 單獨的那一個可能出現1到6的點數,我們需要計算從1-6的每一種點數和剩下的n-1個骰子來計算點數和。
- 還是把n-1個那部分分成兩堆,上一輪的單獨骰子點數和這一輪的單獨骰子點數相加,然后再和剩下的n-2個骰子來計算點數和。
定義一個長度為6n-n+1的數組,和為s的點數出現的次數保存到數組的第s-n個元素里。
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
#include <iostream>
#include <cstdio> using namespace std; int g_maxValue = 6; 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); } } } void Probability( int number, int *pProbabilities) { for ( int i = 1; i <= g_maxValue; ++i) { Probability(number, number, i, pProbabilities); } } void PrintProbability( 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); } delete[] pProbabilities; } int main() { PrintProbability( 6); return 0; } |
思路二:
基於循環求骰子點數,時間性能好。
- 用兩個數組來存儲骰子點數的每一種出現的次數。
- 在一次循環中,第一個數組中的第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
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
#include <iostream>
#include <cstdio> using namespace std; int g_maxValue = 6; void PrintProbability( 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; ++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]; } int main() { PrintProbability( 6); return 0; } |