12.集合的划分

信息学奥赛一本通(C++版)在线评测系统


首先我们来想一下放苹果的问题:

这是之前利用搜索做过的题目,现在尝试利用递归的思想来解:

(1) 将m个同样的苹果放入到n个一样的盘子中,比如有7个苹果,7个盘子,1,1,5和5,1,1的方法是相同的,因为盘子都一样,苹果也一样,方案数就重合了,所以在搜索解法中的可行性方案是要进行剪枝和不降序枚举的。

(2)递归的思想,本质上就是将大问题转化成小问题的思想,不去考虑冗杂的数据,重在分析和分类,比如这道题,盘子和苹果的数量的不同,势必会影响整体的拆分方案,设f(m,n)为将m个苹果分成n的方案数

        当m<n的时候,肯定是有空盘子的,最少有m-n个空盘子,那么f(m,n)=f(m,m);

        当m>n的时候,可以有空盘子,也可以没有,如果没有空盘子的话,可以先将n个盘子中每个都放入一个苹果,苹果剩下了m-n个,那么方案数也就是将m-n个苹果放到n个盘子中,

即f(m-n,n);如果有空盘子的话,盘子可以空1个,空2个,空3个...空一个的时候方案数为f(m,n-1)即将m个苹果放到n-1个盘子中,重点来了,那空两个盘子,三个盘子的时候表达式也都要列出来么?不需要,因为递归本质上就是将规模缩小的思想,随着不断递进n-1会逐渐缩小,也就变成了n-2,n-3的规模,即空2个盘子和3个盘子的问题

所以当m>=n的时候,f(m,n)=f(m-n,n)+f(m,n-1)

        当m==n的时候,同样的思路,如果没有空盘子f(m,n)=1,如果有空盘子f(m,n)=f(m,n-1)

即f(m,n)=1+f(m,n-1)

        再来看规模最小的问题,也就是递归的出口,当m==1的时候,不管有多少盘子,方案数也就是1,当盘子为1的时候,不管有多少苹果,方案数也是1。


#include<bits/stdc++.h>
using namespace std;

long long f(int x,int y)
{
	if(x==1||y==1)//当只有一个盘子或者一个苹果的时候
	return 1;//只有1种方案

	if(x<y)//如果苹果数小于盘子数的话
	return f(x,x);

	if(x==y)//如果苹果数等于盘子数的话
	return 1+f(x,y-1);

	if(x>y)//如果苹果数大于盘子数的话
	return f(x-y,y)+f(x,y-1);
}
int main()
{
	int k,m,n;
	cin>>k;

	for(int i=1;i<=k;i++)
	{
		cin>>m>>n;
		cout<<f(m,n)<<endl;
	}
	return 0;
} 

解题思路:

(1)现在再来看一下这道题目, 集合的划分,第一个限定条件,集合不能为空,第二个限定条件,任意两个集合都没有相同的元素,第三个限定条件,所有的集合合起来是原来的大集合

(2)那么本质上就是放苹果的问题,现在有m个不同的苹果,放在n个盘子里,并且每个盘子都不为空,问有多少种方法?

(3)根据递归思路来分类为子问题的话,同样m和n的大小会拆解为不同的分法,如果m<n的话,

必然会有空盘子,那么方案数为0,如果m==n的话,每一个盘子放一个苹果,方案数为1,如果m>n的话,因为苹果都是不相同的,先拿出一个苹果来,如果这个苹果单独放一个盘子的话,方案数为f(m,n)=f(m-1,n-1),如果这个苹果和其他苹果在一个盘子里,先将m-1个苹果放到n个盘子中,这一个苹果放到哪里呢?他有n种选择,因为苹果是不一样的!即f(m,n)=f(m-1,n)*n

所以得到f(m,n)=f(m-1,n-1)+f(m-1,n)*n;


#include<bits/stdc++.h>
using namespace std;

long long f(int x,int y)
{
	if(x==y||y==1)//如果只有1个盘子或者苹果等于盘子 
	return 1;
	
	if(x<y)//如果盘子大于苹果数 
	return 0;
	
	if(x>y)//如果苹果树大于盘子 
	return f(x-1,y-1)+f(x-1,y)*y;
}
int main()
{
	int m,n;
	cin>>m>>n;
	cout<<f(m,n);
	return 0;
}

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值