Problem Description
小晴天的后花园有好多好多的苹果树,某天,苹果大丰收~小晴天总共摘了M个苹果,我们假设苹果之间是不可分辨的。
为了保存苹果,小晴天买了N个一模一样的箱子,想要把苹果放进去,允许有的箱子是空的,请问小晴天有多少种不同的放法呢?
例如对于4个苹果,3个箱子,2+1+1和1+2+1和1+1+2 是同一种分法。
Input
多组数据,首先是一个正整数t(t<=100)表示数据的组数。
每组数据均包含二个整数M和N(1<=M,N<=10)。
Output
Sample Input
1 7 3
Sample Output
8
Hint
对于7个苹果,3个箱子
有7+0+0=6+1+0=5+2+0=4+3+0=5+1+1=4+2+1=3+2+2=3+3+1
这8种放法。
一看到就是像是dp的题目,果不其然,状态转移方程涉及到了互斥事件。首先我们来分类讨论呢,设d[i][j]表示用i个箱子装j个苹果,如果箱子比苹果多,那么肯定会有空的箱子,那么就可以讲这些箱子去掉,不影响结果,仔细想一想,就是说不管怎么样,都会有i-j个箱子空出来,就是这个道理,所以
if (i>j) d[i][j]=d[j][j];
当苹果比箱子多的时候,就可以分成两个部分:首先没有箱子空的,那么把每一个箱子里的苹果拿掉一个,总数是不变的,因为题目设定 1 2 1 和 1 1 2 是一种,所以说在全部减一的情况下不会和其他情况重复,这个有点难理解,真不知道是谁想到的= =,所以一共有d[i][j-i]种情况。第二种情况就是至少有一个箱子是空的,那么就好办了,去掉不影响,所以有d[i-1][j]种情况。由于这两种情况互斥,所以一起构成整个事件。
d[i][j]=d[i][j-i]+d[i-1][j];
由此问题就解决了。
AC代码:
// Created by CQUWEL
// Copyright (c) 2015年 Team 3. All rights reserved.
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <algorithm>
#include <cctype>
#include <stack>
#include <queue>
#include <map>
#include <string>
#include <set>
#include <vector>
#define INF 0x3f3f3f3f
#define cir(i,a,b) for (int i=a;i<=b;i++)
#define CIR(j,a,b) for (int j=a;j>=b;j--)
#define CLR(x) memset(x,0,sizeof(x))
typedef long long ll;
using namespace std;
int t;
int m,n; // apple box
int d[15][15]; //i个箱子,j个苹果
int main()
{
cin >> t;
while (t--)
{
scanf("%d%d",&m,&n);
for (int i=0;i<=n;i++)
for (int j=0;j<=m;j++)
d[i][j]=1;
for (int i=2;i<=n;i++)
for (int j=2;j<=m;j++)
{
if (i>j) d[i][j]=d[j][j];
else if(i<=j)
d[i][j]=d[i-1][j]+d[i][j-i];
}
cout << d[n][m]<< endl;
}
return 0;
}