lintcode 骰子求和
阿新 • • 發佈:2019-01-27
/*
今天被問到了一道lintcode上的題目,然而想了好久才想明白,看來在STL處折騰得太久,當初看《挑戰》時,粗淺地學的一點點動態規劃,已經忘得所剩無幾了...
這幾天開始上課了,寫acm題的時間又被壓縮,不過還是盡力每天至少做一道演算法題,保持題感。
此外,最近開始學java,偶爾也發些java的程式碼到部落格,由於剛入門java,程式碼會比較簡單,不過還是爭取每天保證相當的程式碼量,併發出來,激勵自己每天都要多花時間程式設計
*/
class Solution { public: /** * @param n an integer * @return a list of pair<sum, probability> */ vector<pair<int, double>> dicesSum(int n) { // Write your code here vector<pair<int, double>> results; double f[n + 1][6 * n + 1]; memset(f, 0, sizeof(f)); for (int i = 1; i <= 6; ++i) f[1][i] = 1.0 / 6; for (int i = 2; i <= n; ++i) // 第 i 個骰子的點數和情況,其情況由前 (i-1) 個 骰子的點數和推出 for (int j = i; j <= 6 * i; ++j) // i 個骰子的點數和範圍,必定為 [i, 6i],全為1和全為6時,分別取得上下界 { for (int k = 1; k <= 6; ++k) // 第 n 個骰子的點數只可能為 1到6 if (j > k) // j-k 必須嚴格大於0 (因為在這題中,由於i和j的實際意義分別為,投擲次數,和點數總和,所以兩者的最小值都不可能取到0) f[i][j] += f[i - 1][j - k]; //相應的,前(n-1)個骰子的點數和,就是 j-k,累加是為列舉所有能湊出 點數和為 j 的情況,並將出現概率求和 f[i][j] /= 6.0; // 在沒有除以6之前,表示的是在最後一次擲出k點的情況下,n 次投擲得到的點數和為 j 的概率 } /* 解釋下 f[i][j] /= 6.0; 這句程式碼; ** 我覺得是用到了"條件概率公式",P(A) = P(A|B)* P(B) ** 在 f[i][j] 還沒有除以6時,它的意思是,在滿足第n次擲出k點的情況下,n次總共透出點數和為j的概率,即為P(A|B) ** 而擲出k的概率,由於點數 k 在 1~6之間等可能分佈,故為 1/6 ** 所以除以6以後,它才是真正的 P(A),其實本來該是在 f[i][j] += f[i - 1][j - k]; 句除以6,表示 "每種能湊出點數總和為 j 的情況出現的概率之和",但既然先只是累加求和,求完和除以6,也是一樣的,畢竟乘法有分配律 ** */ for (int i = n; i <= 6 * n; ++i) //n個骰子點數和範圍必為[n,6n],只要將對應的double陣列的元素組成pair壓棧返回即可 results.push_back(make_pair(i, f[n][i])); return results; } };