1. 程式人生 > >【測評中的編程題】組合數相關的問題

【測評中的編程題】組合數相關的問題

操作 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>(), int
cnt = 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)為例,輸出結果如下

技術分享圖片

【測評中的編程題】組合數相關的問題