苹果放在盘子里(动态规划问题)

  1. m个相同的苹果放在n个相同的盘子里,允许有空盘子
  2. m个相同的苹果放在n个相同的盘子里,不允许有空盘子
  3. m个相同的苹果放在n个不同的盘子里,允许有空盘子
  4. m个相同的苹果放在n个不同的盘子里,不允许有空盘子

第一种情况
设f(m,n) 为m个苹果,n个盘子的放法数目,则先对n作讨论,
如果n>m,必定有n-m个盘子永远空着,去掉它们对摆放苹果方法数目不产生影响;即  if(n>m) f(m,n) = f(m,m)  
当n<=m时,不同的放法可以分成两类:即有至少一个盘子空着或者所有盘子都有苹果,

前一种情况相当于f(m,n) = f(m,n-1); 
后一种情况可以从每个盘子中拿掉一个苹果,不影响不同放法的数目,即f(m,n) = f(m-n,n). 
而总的放苹果的放法数目等于两者的和,即f(m,n) =f(m,n-1)+f(m-n,n)。

边界条件为m=0或n=1时,只有一种放法。

#include<iostream>
using namespace std;

int fun(int m,int n){
    // 没有苹果 或者 只有一个盘子
	if(m==0||n==1)
		return 1;
		
	if(m<n)
		return fun(m,m);
		
	else
		//if((m-n)<=1||n==1)
		//return 1;
		return fun(m,n-1)+fun(m-n,n);	
}
int main(){
	int m,n,t;
	cin>>t;
	while(t--){
		cin>>m>>n;
		cout<<fun(m,n)<<endl;
	}
	return 0;
}

第二种情况
盒子不能为空,所以可以当成将m-n个球放到n个盒子里,盒子可以为空。

比如将10个球放到5个盒子里,可以当成5个球放到5个盒子里,盒子能为空。接着,再分情况,将球分为

(5,0,0,0,0)

(4,1,0,0,0)或(2,3,0,0,0)

(3,1,1,0,0)或(2,2,1,0,0)

(2,1,1,1,0)

(1,1,1,1,1)
也就是1个盒子不能为空,2个盒子不能为空,3个盒子不能为空,到5个盒子都不能为空。

用一个函数fun(m,n)来获取m个球放到n个盒子里不能为空的情况(也可以用能为空的,这里用的是不能为空的)

上面的可以转换成

fun(5,1)+fun(5,2)+fun(5,3)+fun(5,4)+fun(5,5)

#include <iostream>
using namespace std;
 
int fun(int m, int n) {
    if (m < n)   //m<n返回0
         return 0;
         
    if (n == 1 || (m - n) <= 1) //盒子为1时,球只有一个或0(0个即球刚好均分),时都只有一种分配方法
        return 1;
 
    int s = 0, count;   //s记录总数,count为递归次数
 
    if (m - n < n)       //去掉每个盒子分配的一个球后,球的数量少于盒子数,则只要递归球的个数次
        count = m - n;   //球数少的情况
    else
        count = n; //盒子数少的情况
 
    for (int i = 1; i <= count; i++) {
        s += fun(m - n, i); //递归
    }
 
    return s;
}
 
int main(int argc, char **argv) {
 
    cout << "\t";
    for (int i = 1; i <= 15; i++) {
        cout << i << "\t";
    }
    cout << endl;
 
    for (int i = 1; i <= 15; i++) {
        cout << i << "\t";
        for (int j = 1; j <= 15; j++) {
            cout << fun(i, j) << "    ";
        }
        cout << endl;
    }
}

第三种情况
思路和盘子不同是差不太多,只是多了一个组合数(在这里用Comd(n, m), 表示从n个中选出m个)。
开始分为两种可能:
当 m < n 时,m个苹果可以在n个盘子里选m个,也就是Comd(n, m)个,身下的(n-m)个盘子已经被考虑过了,而且不会影响接下来的摆放,直接去掉就行,所以方法数有 Comd(n, m) * f(m, m)

当 m >= n时,分为有盘子为空(有0)和盘子均不为空(无0):
有0时:从n个盘子中选出一个不放苹果,有Comd(n, 1)种选法,所以就是Comd(n, 1) * f(m, n-1)
无0时,从m个苹果中先拿出n个放满盘子,这n个苹果对后序摆放没有一点影响,直接去掉就行,然后就变成了(m-n)个苹果摆放在n个盘子问题 也就是 f(m-n, n)

递归出口(同盘子相同时一样)

int f(int m, int n)
{
	if (m==0 || n==1)
	{
		return 1;
	}
	else if (m < n)
	{
		return Comd(n, m) * f(m, m);
	}
	else if (m >= n)
	{
		return Comd(n, 1)*f(m, n-1) + f(m-n, n);
	}
}


第四种情况

#include <iostream>
using namespace std;
 
int fun(int m, int n) {
    if (m < n)   //m<n返回0
         return 0;
         
    if (n == 1 || m==n)
        return 1;
    if ((m - n) == 1) //盒子为1时,球只有一个或0(0个即球刚好均分),时都只有一种分配方法
      return  n;
    int s = 0, count;   //s记录总数,count为递归次数
 
    if (m - n < n)       //去掉每个盒子分配的一个球后,球的数量少于盒子数,则只要递归球的个数次
        count = m - n;   //球数少的情况
    else
        count = n; //盒子数少的情况
 
    for (int i = 1; i <= count; i++) {
        s += Comd(n, count)*fun(m - n, i); //递归
    }
 
    return s;
}
  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 这是一个经典的组合问题,可以用数学公式来表示: 将m个同样的苹果放在n个同样的盘子,每个盘子可以为空,共有多少种不同的放法? 答案是:C(m+n-1, n-1),其中C表示组合数,即从m+n-1个位置中选出n-1个位置放置盘子的方案数。 例如,将4个苹果放在3个盘子,共有C(6,2)=15种不同的放法: 4 3 1 2 2 2 1 1 1 1 2 3 1 2 2 1 3 1 2 1 4 3 1 2 2 1 3 4 希望能帮到您! ### 回答2: 题目中提到要把m个同样的苹果放在n个同样的盘子,这是一个比较简单的排列组合问题,可以通过以下的步骤进行解答。 假设m个苹果放在n个盘子,我们可以先不考虑每个盘子有几个苹果,这样就有以下两种情况: 1. 每个盘子都为空:这种情况下,我们只需要从n个盘子中选出一个空的盘子,所以有n种情况。 2. 至少有一个盘子放了苹果:这种情况下,我们需要先从n个盘子中选出一个盘子放置第一个苹果,第一个苹果可以放在n个盘子中的任意一个盘子,所以有n种情况;接着从n个盘子中选出一个盘子放置第二个苹果,第二个苹果也可以放在n个盘子中的任意一个盘子,所以有n种情况;一直往下选,直到把m个苹果都放进盘子为止,最后的情况数是n的m次方。这是因为每次放苹果的时候,我们都可以选择n个盘子中的任意一个,所以总的情况数就是n的m次方。 但是,在第二种情况中,同样的苹果分配到不同的盘子中实际上是算重复的情况,因此需要用组合数的方式进行计算。假设有m个苹果需要放置在n个盘子中,我们可以使用组合数的公式来计算方案数: C(m+n-1,n-1) 其中,C表示组合数,m+n-1表示总共需要做的选择数,n-1表示需要做出的选择数。这个式子的含义就是,在放苹果的过程中,假设我们在m-1个苹果之间插入n-1个隔板,每个隔板表示一种分配方案。这样我们可以将这个问题转化为一组需要从m+n-1个物品中选择n-1个物品的问题,也就是上面的组合数公式。 通过上述的步骤,我们就可以得出将m个同样的苹果放到n个同样的盘子中的方案数。此外,还有一些与这个问题相关的变种问题,比如说考虑每个盘子中至少有一个苹果的情况,这个时候我们可以使用插板法计算方案数,得到的结果是: C(m-1,n-1) 这个式子的含义是,我们需要从m-1个苹果中选择n-1个隔板,将这n个隔板放在m个苹果之间,这样就将m个苹果分成了n组,每组至少有1个苹果。 ### 回答3: 假设我们有m个同样的苹果,n个同样的盘子,我们想把这些苹果放到盘子。这是一个典型的组合问题,我们可以探讨以下两种情况。 1. 盘子数不足以装下所有苹果 如果盘子的数量小于苹果的数量,也就是n<m,那么有些盘子是空的或者有苹果没办法放进去。在这种情况下,我们可以采用经典的“隔板法”来计算。我们可以先把n-1个隔板排成一排,表示把n个盘子分为n-1组。在隔板之间插入m个苹果,这样每组之间的苹果数量就是把苹果放入盘子的方案数。具体的计算公式为:(m+n-1)C(n-1),其中C表示组合数。 例如,我们有5个苹果和3个盘子。我们可以插入2个隔板,这样就分成了3组,即3组(2,1,2),(4,0,1)和(1,3,1),表示有2个苹果放在第一个盘子,1个苹果放在第二个盘子,2个苹果放在第三个盘子等。这样的方案数为:(5+3-1)C(3-1)= 28。 2. 盘子数足以装下所有苹果 如果盘子的数量不小于苹果的数量,也就是n≥m,那么每个盘子至少放一个苹果。我们可以采用递归的方法来进行计算。 首先,我们把一个苹果放在每个盘子,这样就放了n个苹果。此时我们还剩下m-n个苹果需要放。如果剩下的苹果数量为0,那么就找到了一种方案。否则,我们需要在已经放了一个苹果盘子再放苹果。 可以注意到,此时需要放苹果盘子数目不超过剩余的苹果数目。例如,如果还剩下3个苹果,需要放的盘子数目最多为3个,因为放在4个或者更多的盘子,至少有一个盘子是空的,无法放苹果。 因此,我们可以枚举需要放苹果盘子数量k,然后从n个盘子中选出k个盘子来装作需要再放苹果盘子。然后把剩余的苹果放到这k个盘子中去。由于剩余的苹果数量比k还小,因此可以递归调用放苹果的函数来计算。具体的计算公式为: F(m,n) = SUM(from k=1 to m) C(n, k) * F(m-k, n-k) 其中C(n, k)表示从n个盘子中选出k个盘子的组合数,F(m-k, n-k)表示把剩余的苹果放到k个盘子的方案数。 例如,如果有5个苹果和3个盘子,我们先把每个盘子放一个苹果,然后剩余2个苹果需要再放。我们假设需要再放1个盘子苹果,也就是目前有2个苹果需要放进2个盘子。根据公式,我们可以计算得到方案数为:C(3,1) * F(1,2) = 3。其中F(1, 2)表示把1个苹果放在2个盘子的方案数,为2。因此,总的放苹果方案数为8。 总之,把m个同样的苹果放入n个同样的盘子是一个经典的组合问题,可以采用“隔板法”或者递归的方法来计算。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值