ACM学习感悟——暴力专场F(dp)

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;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值