网格-递归作业2-放苹果问题

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

关于输入
第一行是测试数据的数目t(0<= t <= 20),其后的t行均包含两个整数M和N,以空格分开。
1<= M <= 25;
1<= N <= 10;

关于输出
对输入的每组数据M和N,用一行输出相应的K

例子输入
1

7 3
例子输出
8
提示
采用递归思想解题。

代码:

 1 //放苹果问题
 2 //2019-11-18
 3 #include<iostream>
 4 using namespace std;
 5 //跟数的划分一个思路,小区别在于允许有空的篮子。可以用搜索或者动规 
 6 int m, n; //把m划分为n份 
 7 int ans; //用于存答案 
 8 void dfs(int step,int x, int left){ //子问题需要用什么参数刻画?划分到第step个数,还剩x +当前数是几
 9     if(step==n-1&&x>=left){ //如果已经划分到倒数第二个数了,并且剩下的数比当前数大,就成为一种分法 
10         ans++; 
11     }
12     else{
13         for(int i = left; i <= x; i++) //还需要知道当前划分出的数是几,来决定i从几开始循环.i表示分出来的下一个数是啥 
14             dfs(step+1,x-i,i); 
15     }
16 } 
17 int main(){
18     int t;
19     cin>>t;
20     while(t--){
21         ans = 0; //注意多组数据输入时的初始化 
22         cin>>m>>n;
23         dfs(0,m,0);
24         cout<<ans<<endl;
25     } 
26     return 0;
27 } 

备注:

这道题和https://www.cnblogs.com/fangziyuan/p/5934345.html这道数的划分是类似的。唯一的区别在于是否能有空篮子,但这也不重要,不管是对动规还是搜索。

对于动规来说,动态转移方程和不能有0就有一点变化:(转+改)

设f[m][n]为将m分成最多n份的方案数,且其中的方案不重复。
则有:
f[m][n] = f[m][n - 1] + f[m - n][n];
           = 1 // m== 0 || n == 1
           = 0 // m < 0
f[m][n - 1]相当于第一盘子中为0,只用将数分成n - 1份即可。因为0不会大于任何数,相当于f[m][n - 1]中的方案前面加一个为0的盘子,而且不违背f的定义。所以f[m][n - 1]一定是f[m][n]的方案的一部分,即含有0的方案数。
f[m - n][n]相当于第一个盘子不为0.那么把每个盘子的数-1,方案数是不变的,相当于用n个数去凑m-n

 

posted @ 2019-11-18 16:39  timeaftertime  阅读(213)  评论(0编辑  收藏  举报