1. 程式人生 > >做題感悟:放蘋果

做題感悟:放蘋果

其實,這道題在一開始我就想到了正確解法的一部分,但是因為某閆同學而否定了自己(畢竟只想到了一部分)。

好的我們先來看一下這道題:

放蘋果

總時間限制: 
1000ms
 
記憶體限制: 
65536kB
描述
把M個同樣的蘋果放在N個同樣的盤子裡,允許有的盤子空著不放,問共有多少種不同的分法?(用K表示)5,1,1和1,5,1 是同一種分法。
輸入
第一行是測試資料的數目t(0 <= t <= 20)。以下每行均包含二個整數M和N,以空格分開。1<=M,N<=10。
輸出
對輸入的每組資料M和N,用一行輸出相應的K。
樣例輸入
    1
    7 3
樣例輸出
    8
好的,先說一下我一開始想到的:
  首先,這道題是一個十分典型的遞迴題,至於為什麼我就不說了,你們都知道。因此,先找到這道題的出口:當僅剩一個盤子(所有剩的蘋果都放在一個盤子裡)或沒有蘋果(所有盤子都空)時,都只有一種可能。因此,將f(m)拆分開成f(m-1)+n,依次遞迴下去。
很顯然,這並不成立
比如:如果有盤子不放蘋果呢?
好吧,不賣關子了,直接說正確思路:
  首先,遞迴出口已經找到,那麼下一個目標就是拆分可能性,依次遞迴,直到滿足出口條件(m==0||n==1)時遞歸回來。
  那麼,可能性如何拆分呢?
  我們知道對於m個蘋果,只有兩大類情況:每個盤子都有和有空盤子。那麼我們是不是可以拆分f(m,n)=f(m-n,n)+f(m,n-1)呢?
  
顯然成立
但是,細心的朋友會發現:當m<n時,m-n居然成了負數
?!
原因是:當蘋果數小於盤子數時,你居然還要求人蘋果把盤子填滿?這很顯然是錯誤的。所以我們就可以將問題轉化為m個蘋果放在m個盤子中(題目中說過順序不重要),因此,我們要加一個特判。
好的,我講完了?
並沒有!
補充一句:當m<n時,你覺不覺得接下來就會到達一個出口呢?
好吧,這並不重要。。。
最後,附上本題程式碼
#include<cstdio>
using namespace std;
int fang(int m,int n)
{
    if(m==0||n==1)
    {
        return 1;
    }
    else if(m<n)
    {
        return fang(m,m);
    }
    else
    {
        return fang(m-n,n)+fang(m,n-1);
    }
}
int main()
{
    int t,M,N;
    scanf("%d",&t);
    for(int i=1; i<=t; i++)
    {
        scanf("%d%d",&M,&N);
        printf("%d\n",fang(M,N));
    }
    return 0;
}