一个很纠结的问题!

houzhenghui123 2010-12-08 12:45:44
题目:
把M个同样的苹果放在N个同样的盘子里,允许有的盘子空着不放,问共有多少种不同的分法(用K表示)?注意:5,1,1和1,5,1是同一种分发。

这显然是个数学问题:加入苹果用*,盒子用| 来表示,五个苹果和三个盒子
问题转换为:*****||(*相当于苹果,|相当于隔板,两个隔板分成三份)
就是这七个玩意儿全排列:7!
由于:5,1,1和1,5,1是同一种分发,所以排列和苹果和隔板的顺序无关
分法的总数为:7!/5!/2!
对应M和N就是:(M+N-1)!/M!/(N-1)!
在有个递归代码如下,我彻底的纠结了!

int f(int n,int m)//m代表苹果,n代表盘子
{
int dev;
if(n==1||m==0)
return 1;
if(n>m)
{
dev=f(m,m);
return dev;
}
else
{
dev=f(n-1,m)+f(n,m-n);
return dev
}
}

。。。。。:我看别人的解释压根弄不明白各句代码代表神马?请各位好心人用*代表苹果,|代表盒子距离说明下!我承认我智商低,讲的清晰点!明白点!小菜在这里谢谢了!
...全文
156 12 打赏 收藏 转发到动态 举报
写回复
用AI写文章
12 条回复
切换为时间正序
请发表友善的回复…
发表回复
houzhenghui123 2010-12-08
  • 打赏
  • 举报
回复
检查了下!没有错字,嘿嘿!
pengzhixi 2010-12-08
  • 打赏
  • 举报
回复
int f(int n,int m)//m代表苹果,n代表盘子
{
int dev;
if(n==1||m==0)
return 1;
if(n>m)//盘子比苹果多,那么m个苹果,n个盘子的放法和m个苹果m个盘子的方法是一样的。
{
dev=f(m,m);
return dev;
}
else
{
dev=f(n-1,m)+f(n,m-n);//苹果比盘子多就分两个情况,有空盘子和没空盘子,有空盘子的话那么就是f(n-1,m);没空盘子就是f(n,m-n)(先将每个盘子放一个,然后将m-n个放到n个盘子上)。两者之和就是答案
return dev
}
}
houzhenghui123 2010-12-08
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 zhao4zhong1 的回复:]
“给定一个小点的输入,完整单步跟踪一遍。”是理解递归函数工作原理的不二法门!
[/Quote]
你说的方法的确,但是这个问题我主要是思路不是清晰,若思路清晰了,递归不是说问题\!
qq120848369 2010-12-08
  • 打赏
  • 举报
回复
#include <iostream>
using namespace std;

int n; //盘子总数

int f(int m,int cur) //表示m个苹果,当前处于第cur个盘子总共有多少种方法
{
//如果放到了最后一个盘子,cur==n,那么只有将剩下的苹果都放进最后一个盘子
//如果没有苹果(注意:有苹果的情况下,下面两种递归都会处理得当!!),那么方案只有1种,就是不放苹果
if(cur==n || m==0)
{
return 1;
}


//如果苹果不足,我们可以直接放到相应的盘子,不用再试探了,同时也避免了###处m-(n-cur+1)为负数的情况
if(n-cur+1 > m) //cur以及之后的盘子比苹果还多,那么只能把这些苹果放到最后m个盘子里保证count[i]<=count[i+1]
{
return f(m,n-m+1); //n-m是最后m个盘子的开始下标
}


//苹果足够,放当前第cur个盘子,有两种方案
return
f(m,cur+1)
//第cur盘子不放苹果,那么就再也不放了,所以cur+1,你可以试想如果cur不+1,会无限递归f(cur+1,m),这一层递归的作用
//其实是停止放第cur个盘子的意思,如果你执行下边那一句递归若干次,即给cur盘子以及之后放了若干次苹果之后,通过这一个
//递归就可以进入到cur+1盘子开始继续做
+f(m-(n-cur+1),cur); //#############
//第cur盘子放苹果,为了不出现重复的情况,必须给cur以及之后的所有盘子都放一个苹果,一共花费了
//n-cur+1个苹果,所以给m-(n-cur+1)就是剩下的苹果,cur保持不变,意思是我们下一次依旧在cur盘子进行抉择放或者不放
}

int main()
{
n=3;

cout<<f(3,1)<<endl; //3个苹果放入3个盘子

return 0;
}


便于理解,改成顺着盘子序号逐次放苹果的形式.
ljwfp 2010-12-08
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 thefirstz 的回复:]
n个盘子,m个苹果的组合,可以分解为两种情况:
1,有一个空盘子,规模变为n-1,m
2,没有空盘子,也就是每个盘子有一个苹果,规模就变为n,m-n

于是产生递归了
[/Quote]

这个描述大体是对的,但是纠正一下,1不是有一个空盘子,规模变为n-1,m,是所有有空盘子的情况归结为n-1,m
赵4老师 2010-12-08
  • 打赏
  • 举报
回复
“给定一个小点的输入,完整单步跟踪一遍。”是理解递归函数工作原理的不二法门!
houzhenghui123 2010-12-08
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 qq120848369 的回复:]
是组合,不是排列,只要保证从1...n箱子,count[i]<=count[i+1],就保证没有重复了.

所以,f(n,m)的时候,你可以选择不放在当前的盘里,那么就是f(n-1,m),那么这个盘子之后的盘子依旧可以放0个以及以上的苹果,没有重复情况.

你也可以放苹果,但必须保证count[i]<=count[i+1],所以要放就全放一遍,所以是f(n,m-1),此时所有的盘子都有1个……
[/Quote]
还是没有懂!化下图,把思路阐述清楚,去上课了,下课了来结贴!谢谢哦
昵称很不好取 2010-12-08
  • 打赏
  • 举报
回复
n个盘子,m个苹果的组合,可以分解为两种情况:
1,有一个空盘子,规模变为n-1,m
2,没有空盘子,也就是每个盘子有一个苹果,规模就变为n,m-n

于是产生递归了
applecyl038 2010-12-08
  • 打赏
  • 举报
回复
你看不懂的是这里吧:
else
{
dev=f(n-1,m)+f(n,m-n);
return dev
}
他是分成 有空盘子 和 没有空盘子 来算的, 这两类的分法的和就是 总的分法。
f(n-1,m) : 表示如果存在有空盘子的分法, 也就是用剩下的n-1个盘子来装着m个苹果。
f(n, m - n):表示没有空盘子的分法,即每个盘子至少有1个苹果,那已经用掉了n个苹果,只要把剩下的
m - n 个苹果分在这n个盘子里就行了。

qq120848369 2010-12-08
  • 打赏
  • 举报
回复
   if(n>m)
{
dev=f(m,m);
return dev;
}


这里的意思是:如果还没有抉择过的盘子有n个,而n>m,那么这m个苹果只能放在n个盘子里中最后m个里,所以就是f(m,m);
qq120848369 2010-12-08
  • 打赏
  • 举报
回复
\纠正,倒数第三行:f(n,m-n)
qq120848369 2010-12-08
  • 打赏
  • 举报
回复


是组合,不是排列,只要保证从1...n箱子,count[i]<=count[i+1],就保证没有重复了.

所以,f(n,m)的时候,你可以选择不放在当前的盘里,那么就是f(n-1,m),那么这个盘子之后的盘子依旧可以放0个以及以上的苹果,没有重复情况.

你也可以放苹果,但必须保证count[i]<=count[i+1],所以要放就全放一遍,所以是f(n,m-1),此时所有的盘子都有1个,依旧满足没有重复.


懂了么?

64,635

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧