苹果放盘子问题

2019.6.5
苹果放盘子问题,有盘子若干,苹果若干,盘子与苹果都完全相同,例如7个苹果,放入3个盘子,允许盘子为空,共有多少种方法?115和511是相同的方法,7个苹果3个盘子,答案是8种。

<一>暴力枚举
分析:手动枚举防止重复的方法就是通过有序排列,而选择从大到小的排序方法效率更高。
优点: 可以改造成可以打印出所有的排序情况的代码
注意点:++c表示的是指针所指向的数字加1,而c++表示的指针的位置向后移一位

#include<stdio.h>
void solve(int a,int b,int* c,int last)
{
   if(b==1)
   {
      if(a<=last&&a>=0) ++*c;
       return;
   }
   if(a==0){++*c;return;}
   
   int minn=last;
   if(a<minn)minn=a;
   for(int i=minn;i>0;i--)solve(a-i,b-1,c,i);
}
int main(void)
{
    int apple,dish,ans=0;
    scanf("%d %d",&apple,&dish);
    solve(apple,dish,&ans,apple+1);
    printf("共有%d种排序方法",ans);
    return 0;
}

改造成可打印排列的如下

#include<stdio.h>
int min(int a,int b){if(a<b)return a;  return b;}
void print(int arr[],int cnt)
{
    for(int i=0;i<cnt;i++)printf("%d ",arr[i]);
    printf("\n");
}
int solve(int a,int b,int* c,int last,int arr[],int cnt)
{
   if(b==1)
   {
      if(a<=last&&a>=0){++*c;arr[cnt]=a;print(arr,cnt+1);return 1;}
       return 0;
   }
   if(a==0){++*c;print(arr,cnt);return 1;}
   for(int i=min(a,last);i>0;i--)
    {
        arr[cnt]=i;
          solve(a-i,b-1,c,i,arr,cnt+1);
}
}
int main(void)
{
    int apple,dish,ans=0,arr[100];
    scanf("%d %d",&apple,&dish);
    solve(apple,dish,&ans,apple+1,arr,0);
    printf("共有%d种排序方法",ans);
    return 0;
}


<二>抓住本质写递归 --------from 硕硕
作者思路:首先是当盘子数目大于苹果数目时,多余的盘子是没有用的,所以这时候可以把多于的盘子拿走。当盘子数小于等于苹果数时,可以分为两种情况,有一个空盘子即有0存在的情况,跟所有盘子中都有苹果的情况。对于有0存在的情况,这个盘子存在和不存在并不影响分类数目,可以直接把这个盘子拿走。对于每个盘子中都有苹果的情况,从每个盘子中各拿走一个苹果后,也不影响分类数目。最后当没有苹果或者只有一个盘子的时候就是一种情况即(0个苹果b个盘子)(a个苹果1个盘子)。

我的理解:只有2个选择,要么处理苹果,要么处理盘子,处理苹果意味着把当前的盘子都放上一个苹果,处理盘子意味着减少一个盘子,去看少一个盘子的问题怎么处理,也就是另一个递归了。递归终止就是盘子数为1或者没有苹果了。

优点:运行速度快,效率高,比第一种方法快的多。

#include<stdio.h>
int solve(int a,int b)
{
    if(a==0||b==1)return 1;
    if(a<b)return solve(a,b-1);
    else return solve(a,b-1)+solve(a-b,b);
}
int main(void)
{
    int a,b;
    scanf("%d %d",&a,&b);
    int ans=solve(a,b);
    printf("%d",ans);
}

<三>递推公式
思路:偶然看到某位dl博客用的是递推公式。

#include<stdio.h>
int main(void)
{
    int a,b;
    scanf("%d %d",&a,&b);
    int all[100][100];
    for(int i=0;i<=a;i++)
    for(int j=0;j<=b;j++)
    {
     if(i==0||j==1){all[i][j]=1;continue;}
        if(i>=j)all[i][j]=all[i-j][j]+all[i][j-1];
    else all[i][j]=all[i][j-1];
    }
    printf("%d ",all[a][b]);
    return 0;
}


测试代码放这里了
https://github.com/Mally-cj/mine/commit/9d463e9afd15e32a7b6c55fb6c46aed719a310ed

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
动态规划是一种常用的算法思想,可以用来解决一些具有重叠子问题和最优子结构性质的问题。在解决苹果问题时,可以使用动态规划来求解。 假设有m个苹果和n个盘子,要求将这些苹果盘子中,每个盘子可以为空,但每个盘子中至少要有一个苹果。问有多少种置方式? 首先,我们可以考虑边界情况,当只有一个盘子时,无论有多少个苹果,只有一种置方式。当只有一个苹果时,无论有多少个盘子,也只有一种置方式。 接下来,我们考虑一般情况。假设有m个苹果和n个盘子,我们可以将问题分为两种情况: 1. 至少有一个盘子为空:此时,我们可以将问题转化为将m个苹果入n-1个盘子中的问题,即f(m, n-1)。 2. 所有盘子都有苹果:此时,我们可以将每个盘子中的苹果数量减少一个,即将问题转化为将m-n个苹果入n个盘子中的问题,即f(m-n, n)。 因此,我们可以得到递推公式: f(m, n) = f(m, n-1) + f(m-n, n) 根据递推公式,我们可以使用动态规划来求解苹果问题。我们可以使用一个二维数组dp来保存中间结果,其中dp[i][j]表示将i个苹果入j个盘子中的置方式数量。 具体的动态规划算法如下: 1. 初始化边界情况:当i=0或j=0时,dp[i][j] = 1。 2. 使用递推公式计算dp数组的其他元素: - 当i>0且j>0时,dp[i][j] = dp[i][j-1] + dp[i-j][j]。 最终,dp[m][n]即为将m个苹果入n个盘子中的置方式数量。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

是Mally呀!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值