(动态规划)A - 放苹果

(动态规划)A - 放苹果
把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

*这道题专门问了下数学老师,老师说这道题并没有什么通解,只能一个一个来分着数,因此我想了很久,看了博客中的一种思路,自愧不如,这种思路非常的成熟与有效,如下
解析:
设f(m,n)为m个苹果,n个盘子的放法数目,则先对n作讨论,
   * 当n>m:必定有n-m个盘子永远空着,去掉它们对摆放苹果方法数目不产生影响。即if(n>m)f(m,n)=f(m,m)
   * 当n<=m:不同的放法可以分成两类:
    (a)有至少一个盘子空着,即相当于f(m,n)=f(m,n-1);
    (b)所有盘子都有苹果,相当于可以从每个盘子中拿掉一个苹果,不影响不同放法的数目,即f(m,n)=f(m-n,n).而总的放苹果的放法数目等于两者的和,即f(m,n)=f(m,n-1)+f(m-n,n)递归出口条件说明:当n=1时,所有苹果都必须放在一个盘子里,所以返回1;当没有苹果可放时,定义为1种放法;递归的两条路,第一条n会逐渐减少,终会到达出口n1;第二条m会逐渐减少,因为n>m时,我们会returnf(m,m) 所以终会到达出口m0.
  综上递推公式为:

代码展示

#include<bits/stdc++.h>
using namespace std;
int a[12][12];
int main()
{
    int n,m,t;
    cin>>t;

    while(t>0)
    {
        --t;
        cin>>m>>n;
        a[0][0]=1;
        for(int i=0;i<=m;++i )
        for(int j=1;j<=n;++j)
           {

               if(i<j)   a[i][j]=a[i][i];
               else      a[i][j]=a[i][j-1]+a[i-j][j];
           }
           cout<<a[m][n]<<endl;
    }
    return 0;

}

原博客地址

*然后看了他的题解之后顿时感觉有些简单了,但是,我自己也有一种不成熟的思路,就是将每个盘子中能呈苹果的数量进行评估,递归求解,即将每种可能都给列出来,正是数学老师所提到的,但是总是和答案有所差别,经过无数次调试,发现了多个错误后,写出如下AC代码:

#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
int n,m;
int du(int i,int n1,int a)//i代表此盘子中能呈的最小数量,即前一个盘子中苹果
{				//的数量,n1代表现在还剩下的苹果数,a代表剩下的盘				//子数
	if(a==2)//当盘子数只剩下2个,因为苹果数也确定,故方案数确定
	{
		int t=n1/a-i+1;//方案数即盘子(最大苹果数-最小苹果数+1)
		if(t>0)
		return t;	//这里错过,没有判断是不是负数的情况
		else return 0;
	}
	else
	{
		int ans=0;
		for(int j=i;j<=n1/a;j++)//盘子所能呈的最大数量即剩下的苹果
		{				//数除以盘子数
			ans+= du(j,n1-j,a-1);//将此盘子放j个苹果后,判断放之后
		}				//剩下盘子的方案数
		return ans;
	}
}
int main()
{
	int t;
	cin>>t;
	while(t--)
	{
	cin>>n>>m;
	if(n==1||m==1){cout<<1<<'\n';continue;}//一个盘子或苹果不用考虑多种							//情况
	int ans=du(0,n,m);
	cout<<ans<<'\n';
	}
} 

*无疑,相比起来,还是上一种的思路更加清晰与快捷,更加接近问题本质,但是我所想的方法得以实现也是一种很有成就感的事情,同时满足了自己的求知欲,一个问题可以有多种解法,这也正是算法的魅力。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值