1. 程式人生 > >將m個相同的球全部放到n個相同的盒子裡面有幾種放法

將m個相同的球全部放到n個相同的盒子裡面有幾種放法



盒子不能為空,所以可以當成將m-n個球放到n個盒子裡,盒子可以為空。

比如將10個球放到5個盒子裡,可以當成5個球放到5個盒子裡,盒子能為空。接著,再分情況,將球分為

(5,0,0,0,0)

(4,1,0,0,0)或(2,3,0,0,0)

(3,1,1,0,0)或(2,2,1,0,0)

(2,1,1,1,0)

(1,1,1,1,1)

也就是1個盒子不能為空,2個盒子不能為空,3個盒子不能為空,到5個盒子都不能為空。

是不是跟一開始的時候很像,m個球放到n個盒子不能為空?這時候想到了什麼?對,遞迴。

用一個函式fun(m,n)來獲取m個球放到n個盒子裡不能為空的情況(也可以用能為空的,這裡用的是不能為空的)

上面的可以轉換成

fun(5,1)+fun(5,2)+fun(5,3)+fun(5,1)+fun(5,0)    //其中n為0的情況即剛好每個盒子分到一個球,這個也要算進去

如果有非遞迴方法的,歡迎提出來探討^_^,我自己的理解,不知道對錯,有錯請指出,謝謝!

#include <iostream>  
06.using namespace std;  
07.  
08.int fun(int m, int n) {  
09.    if (m < n)   //m<n返回0  
10.         return 0;  
11.    if (n == 1 || (m - n) <= 1) //盒子為1時,球只有一個或0(0個即球剛好均分),時都只有一種分配方法  
12.        return 1;  
13.  
14.    int s = 0, count;   //s記錄總數,count為遞迴次數  
15.  
16.    if (m - n < n)       //去掉每個盒子分配的一個球后,球的數量少於盒子數,則只要遞迴球的個數次  
17.        count = m - n;   //球數少的情況  
18.    else  
19.        count = n; //盒子數少的情況  
20.  
21.    for (int i = 1; i <= count; i++) {  
22.        s += fun(m - n, i); //遞迴  
23.    }  
24.  
25.    return s;  
26.}  
27.  
28.int main(int argc, char **argv) {  
29.  
30.    cout << "\t";  
31.    for (int i = 1; i <= 15; i++) {  
32.        cout << i << "\t";  
33.    }  
34.    cout << endl;  
35.  
36.    for (int i = 1; i <= 15; i++) {  
37.        cout << i << "\t";  
38.        for (int j = 1; j <= 15; j++) {  
39.            cout << fun(i, j) << "    ";  
40.        }  
41.        cout << endl;  
42.    }