把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

1
7 3

Sample Output

8

题解

该题是典型的dp问题。需要找到子问题。
dp[m][n] 表示把m个苹果放到n个盘子里的方案个数,有两种情况。

  • if m < n ; dp[m][n] = dp[m][m]; 因为苹果和盘子是相同的,所以将m个苹果放到n个盘子和放到m个盘子的方案数是一样的。
  • if m >= n ; dp[m][n] = dp[m][n-1]+dp[m-n][n] 表示,m个苹果放到n个盘子里有两种情况:
    1. 一个盘子为空,m个苹果放到n-1个盘子;
    2. 将n个苹果分别放到n个盘子,然后m-n个苹果放到n个盘子里。

注意

  • dp[0][n] = dp[1][n] = dp[m][1] = dp[m][0] = 1
  • 从 i=2, j=2 开始遍历,可以避免将 dp[0][n] 和 dp[m][0] 的值设置为 0 ,因为设置为 dp[0][n] 是不正确的。eg, dp[2][2] = dp[0][2] + dp[2][1],此处,dp[0][2] 表示将 2 个苹果分别放到 2 个盘子,每个盘子一个。如此,dp[0][2] = 1 。

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43

#include<iostream>
using namespace std;

int dp[12][12];

int main()
{
int t,m,n;
while(cin>>t)
{
for(int k=0;k<t;k++)
{
dp[1][1]=1;
cin>>m>>n;
for(int i=0;i<=m;i++)
dp[i][0]=1;
for(int j=0;j<=n;j++)
dp[0][j]=1;
for(int i=0;i<=m;i++)
dp[i][1]=1;
for(int j=0;j<=n;j++)
dp[1][j]=1;

for(int i=2;i<=m;i++) //此处从i=2,j=2开始遍历比较合理
{
for(int j=2;j<=n;j++)
{
if(i<j)
{
dp[i][j]=dp[i][i];
}else
{
dp[i][j]=dp[i][j-1]+dp[i-j][j];
}
}
}

cout<<dp[m][n]<<endl;
}
}
return 0;
}