標籤:acm 組合 數學
放蘋果
| Time Limit: 1000MS |
|
Memory Limit: 10000K |
| Total Submissions: 25952 |
|
Accepted: 16509 |
Description
把M個同樣的蘋果放在N個同樣的盤子裡,允許有的盤子空著不放,問共有多少種不同的分法?(用K表示)5,1,1和1,5,1 是同一種分法。
Input
第一行是測試資料的數目t(0 <= t <= 20)。以下每行均包含二個整數M和N,以空格分開。1<=M,N<=10。
Output
對輸入的每組資料M和N,用一行輸出相應的K。
Sample Input
17 3
Sample Output
8
Source
[email protected]
將n個相同的小球放入m個相同的盒子,問有多少種方法。
解析:有些題目可以轉化為這樣的題目,比如有n個相同的小球,m個相同的盒子,要求每個盒子裡面至少有k個小球,問一共有多少種方法:http://blog.csdn.net/duanxian0621/article/details/7864791 方法為:預先在每個盒子裡面已經放好k個小球,那麼還剩下n-k*m 個小球,然後就轉化為了,把n-k*m個相同的小球放入m個相同的盒子裡面,有多少種方法。
分情況討論:a[i][j]表示i個小球放入j個盒子的方法數
① 當放入小球後,球數最少的盒子為空白,那麼就相當於,把i個小球放入j-1個盒子裡面,即a[i][j-1]。
② 當放入小球後,球數最少的盒子不為空白,那麼說明每個盒子裡面都至少有一個小球,那麼就預先把每個盒子裡面放入一個小球好了,有 a[i-j] [j]。
所以 ,遞推公式為 a[i][j]= a[i][j-1]+a[i-j][j],這裡是i>=j的。
當i<j的時候,無論怎麼放,肯定會存在空盒,不妨先拿走一個空盒(保證有空盒),然後把i個相同的小球放入剩餘的j-1個相同的盒子中,有a[i][j-1]種方法,所以a[i][j]=a[i][j-1].
綜上:將n個相同的小球放入m個相同的盒子有
當i>=j時,a[i][j]=a[i][j-1]+a[i-j][j];
當i<時,a[i][j]=a[i][j-1],(仔細想想,這裡也可以寫成a[i][j]=a[i][i],因為a[i][i]=a[i][i+1]=a[i][i+2]=a[i][i+3]……..
初始化a數組代碼為:
int a[maxn][maxn];
void prepare()
{
for (int i=0;i<m;i++)
a[i][1]=a[0][i]=1;
for (int i=1;i<maxn;i++)
for (int j=2;j<maxn;j++)
if (j<=i)
a[i][j]=(a[i-j][j]+a[i][j-1])%MOD;
else
a[i][j]=a[i][i]; //其實是a[i][j-1],不過和a[i][i]是一樣的。
}
代碼:
#include <iostream>using namespace std;const int maxn=11;int a[maxn][maxn];void init(){ for(int i=1;i<=10;i++) a[0][i]=1,a[i][1]=1; for(int i=1;i<maxn;i++) for(int j=2;j<=maxn;j++) if(j<=i) a[i][j]=a[i][j-1]+a[i-j][j]; else a[i][j]=a[i][i];}int main(){ init(); int t,n,m; cin>>t; while(t--) { cin>>n>>m; cout<<a[n][m]<<endl; } return 0;}