N個雞蛋放進M個籃子問題


題目:
有N個雞蛋和M個籃子,把雞蛋放到M個籃子里,每個籃子都不能為空。另外,需要滿足:任意一個小於N的正整數,都能由某幾個籃子內蛋的數量相加的和得到。寫出程序,使得輸入一個(N,M),輸出所有可能的分配情況。

 

從題意中應該可以得出,對於(1,1,2,2)和(1,2,1,2)這兩種組合,應該是一樣的。
因而對於這M個籃子中的雞蛋數量,我們用數組basket[M]來表示,我們按照非遞減順序進行排列,即basket[i] <= basket[i+1]

1.我們利用歸納法來總結出一個規律:
   對於前n個籃子,其雞蛋數量總和為Sn,那么對於第n+1個籃子,其雞蛋數量應該滿足:
   basket[n+1] <= Sn + 1,如果basket[n+1] > Sn + 1,那么Sn + 1這個數將無法通過相應的籃子雞蛋數相加來獲得。
   由於是非遞減序列,因而
   basket[n] <= basket[n+1] <= Sn + 1

 

2.我們來證明符合上式的數組能夠滿足條件“任意一個小於N的正整數,都能由某幾個籃子內蛋的數量相加的和得到”。
   當M = 1時,basket[0] = 1,當M=2時,取basket[1] = 1,能夠滿足上述條件。
                                                         取basket[1] = 2,也能夠滿足上述條件。
   假設M = n-1時,滿足上述條件,我們來證明當M = n時亦滿足。
   前n-1個籃子的雞蛋數量總和為Sn-1,此時加上第n個籃子,總和為Sn = Sn-1 + basket[n-1]。即證明Sn - 1,Sn - 2,Sn - 3,Sn - (basket[n-1] - 1)都可以由某幾個籃子內蛋的數量相加的和得到。由於basket[n-1] <= Sn-1,而且小於或者等於Sn-1的數能由某幾個籃子內蛋的數量相加的和得到,所以Sn - 1,Sn - 2,Sn - 3,Sn - (basket[n-1] - 1)亦可得到。
   證畢。

3.對於N和M的值,我們在輸入后即可做一個判斷。
   2.1  當N < M,明顯有籃子為空,因而不符。
   2.2  當N >= M時,第一個籃子必然要放1個雞蛋,其后面的籃子我們按照basket[n] <= basket[n+1] <= Sn + 1取最大值,依次為2,4,8,16......,雞蛋總數為2^M - 1,即M個籃子的雞蛋數量最大值。

   所以M <= N < 2^M

 

4.代碼要點

   4.1 對於函數

void solve(int current_sum, int basket_id, int current_num, int* basket, int N, int M)

   其中current_sum表示當前所有籃子雞蛋的總和,

         basket_id表示當前籃子的序號,
         current_num表示將要放到當前籃子去的雞蛋數量,
         basket, N, M值都是main函數中的原值,在遞歸中這三個參數基本沒變。
   初始化為(0, 0, 1, basket, N, M)表示此時所有雞蛋數量為0,將要把1個雞蛋放進第0個籃子里面。

   4.2 對於函數solve中的

    if ((current_sum + current_num*(M - basket_id)) > N || (current_sum + (current_sum + 1)*((1<<(M - basket_id)) - 1)) < N)
        return;

         我們采用的是搜索中的剪枝技術,即在每次遞歸時,通過預先判斷來看此路是否走得通。

  (current_sum + current_num*(M - basket_id)) > N 表示之后的所有籃子都添加最小雞蛋數量,如果這都大於N,那么肯定不符。
  (current_sum + (current_sum + 1)*((1<<(M - basket_id)) - 1)) < N  表示之后的所有籃子都添加相應的最大值,如果這都小於N,那么肯定也不符。     

        其中(current_sum + 1)*((1<<(M - basket_id)) - 1) 可以這樣解釋:

        假設前面的籃子總和為n,那么緊挨着的后一個籃子里雞蛋數量最大值為n+1,其后的一個籃子最大值為n + (n + 1) + 1 = 2n + 2,這之后的一個籃子的最大值為n + (n + 1) + (2n + 2) + 1 = 4n + 4......(即這里取的都是S+ 1)
        依次類推,我們發現n + 1 + (2n + 2) + (4n + 4) + ...... = (2^count - 1)*(n + 1),count表示相應的籃子數量。

 

5.代碼如下:

N eggs M baskets
 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 
 4 void solve(int current_sum, int basket_id, int current_num, int* basket, int N, int M)
 5 {
 6     if (current_sum == N && basket_id == M)
 7     {
 8         int i;
 9         for (i = 0; i < M; i++)
10             printf("%d\t", basket[i]);
11         printf("\n");
12         return;
13     }
14 
15     if (current_num > N || basket_id >= M)
16         return;
17 
18     if ((current_sum + current_num*(M - basket_id)) > N || 
19         (current_sum + (current_sum + 1)*((1<<(M - basket_id)) - 1)) < N)
20         return;
21 
22     int j;
23     for (j = current_num; j <= current_sum + 1; j++)
24     {
25         basket[basket_id] = j;
26         solve(current_sum + j, basket_id + 1, j, basket, N, M);
27     }
28 }
29 
30 int main()
31 {
32     int N;//the number of eggs
33     int M;//the number of baskets
34     while (scanf("%d%d", &N, &M) != EOF)
35     {
36         if (N < M || N >= 1<<M || M <= 0)
37             printf("Wrong data!\n");
38         else
39             printf("The combinations are as below:\n");
40 
41         int* basket = (int*)malloc(sizeof(int)*M);
42         solve(0, 0, 1, basket, N, M);
43         free(basket);
44     }
45     return 0;
46 }

 

 1 #include <stdio.h>
 2 
 3 void solve(int current_sum, int basket_id, int current_num, int* basket, int N, int M)
 4 {
 5     if (current_sum == N && basket_id == M)
 6     {
 7         int i;
 8         for (i = 0; i < M; i++)
 9             printf("%d\t", basket[i]);
10         printf("\n");
11         return;
12     }
13 
14     if (current_num > N || basket_id >= M)
15         return;
16 
17     if ((current_sum + current_num*(M - basket_id)) > N || 
18         (current_sum + (current_sum + 1)*((1<<(M - basket_id)) - 1)) < N)
19         return;
20 
21     int j;
22     for (j = current_num; j <= current_sum + 1; j++)
23     {
24         basket[basket_id] = j;
25         solve(current_sum + j, basket_id + 1, j, basket, N, M);
26     }
27 }
28 
29 int main()
30 {
31     int N;//the number of eggs
32     int M;//the number of baskets
33     while (scanf("%d%d", &N, &M) != EOF)
34     {
35         if (N < M || N >= 1<<M || M <= 0)
36             printf("Wrong data!\n");
37         else
38             printf("The combinations are as below:\n");
39 
40         int* basket = new int[M];
41         solve(0, 0, 1, basket, N, M);
42         delete[] basket;
43     }
44     return 0;
45 }


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM