【測評中的編程題】組合數相關的問題
阿新 • • 發佈:2018-04-06
操作 rom gpo http dfs 推導 else 直接 編程
最近做測評的過程中碰到兩類求組合數的問題:
1. 求組合數的值的大小
2. 求組合數的排列情況
下面分別來討論
1. 求組合數的值的大小
第一種最直接能想到的辦法,就是用排列組合公式
這樣求固然很快,但是無法對中間值進行操作。換句話說,最後求得的結果會很大,可能導致溢出。
當需要對中間值進行操作的時候,如對進行中間值取模操作,就可以用下面的方法。
第二種方法,利用關系式逐層推導
1 int zuhe(int n, int m) 2 { 3 if (n < m) 4 return zuhe(m, n); 5 vector<vector<int>> v(n + 1, vector<int>(n + 1, 0)); 6 for (int i = 0;i <= n;i++) 7 v[i][0] = 1; //第0列的初始值為1,C(n,0)也返回1 8 cout << 1 << endl; 9 for (int i = 1;i <= n;i++) 10 { 11 cout << 1; 12 for (int j = 1;j <= i;j++) 13 { 14 v[i][j] = v[i - 1][j] + v[i - 1][j - 1]; 15 cout << ‘ ‘ << v[i][j]; 16 } 17 cout << endl; 18 } 19 return v[n][m]; 20 }
以C(5,2)為例,打印出如下的表,在每一步的計算過程中都可以進行取模操作,不用擔心最後結果會非常大。
2. 求組合數的排列情況
思路:利用遞歸,類似dfs
1 void help(int n, int m, set<int> s = set<int>(), intcnt = 0, int from = 1) 2 { 3 if (cnt == m) 4 { 5 for (auto item : s) 6 cout << item << ‘ ‘; 7 cout << endl; 8 return; 9 } 10 else 11 { 12 for (int i = from;i <= n;i++) 13 { 14 if (s.find(i) == s.end()) 15 { 16 s.insert(i); 17 help(n, m, s, cnt + 1, i + 1); //cnt表示set中加入數字的數量(遞歸輪數),from表示下一輪遞歸從數字幾開始 18 s.erase(i); 19 } 20 } 21 } 22 }
同樣以C(5,2)為例,輸出結果如下
【測評中的編程題】組合數相關的問題