算法题放苹果:把M个相同的苹果放到N个完全相同的盘子里,有多少种放法?
文章目录
- 题目描述
- 题解
- 思路1 暴力递归
- 思路2:缓存思想——动态规划来优化暴力递归
题目描述
链接:点我做题
题解
思路1 暴力递归
我们利用递归来解决这个问题,不妨这样思考,假设apples表示当前剩余的苹果数,plates表示当前剩余的盘子数,ways(apples, plates)表示以apples个苹果放进plates个盘子里的方法数。
如果apples==0,说明当前苹果都已经放完了,既然放完了,不管剩不剩盘子,这都是一种放的方法,向上一层返回1;
否则apples不为0的时候,如果plates==0了,盘子已经被用完了但是苹果没放完,这种情况显然是摆放失败了,不是一种摆放的方法,向上一层返回0;
再考虑一种特殊情况,当盘子数大于苹果数时,那么苹果怎样也不可能放到多出来的盘子上,这种情况下的摆放方法数显然和盘子减少为 p l a t e s − a p p l e s plates-apples plates−apples个,apples个苹果的摆放方法数是一样多的,因此
i f ( a p p l e s < p l a t e s ) , w a y s ( a p p l e s , p l a t e s ) = w a y s ( a p p l e s , p l a t e s − a p p l e s ) if (apples <plates),\\ways(apples, plates)=ways(apples,plates-apples) if(apples<plates),ways(apples,plates)=ways(apples,plates−apples)
当剩余的苹果数量大于盘子数量时,我们有两种互斥的摆法:
一种,我们用上所有的盘子,也就是先让所有的盘子都摆上一个苹果,那么这种方式的摆法数量a显然等于 w a y s ( a p p l e s − p l a t e s , p l a t e s ) ways(apples - plates, plates) ways(apples−plates,plates);
另一种方法,我们不用上所有的盘子,那么怎么才能不用上所有的盘子呢?先放弃一个盘子,剩下的盘子是放弃还是保留交给递归来讨论。也就是说,不完全使用所有盘子的摆放方法数量b等于 w a y s ( a p p l e s , p l a t e s − 1 ) ways(apples, plates - 1) ways(apples,plates−1).
这两种情况显然是互斥的,所以他们的方法数可以直接相加,也就是说
i f ( a p p l e s > p l a t e s ) w a y s ( a p p l e s , p l a t e s ) = w a y s ( a p p l e s − p l a t e s , p l a t e s ) + w a y s ( a p p l e s , p l a t e s − 1 ) if (apples>plates)\\ ways(apples,plates)=ways(apples-plates,plates)\\+ways(apples, plates-1) if(apples>plates)ways(apples,plates)=ways(apples−plates,plates)+ways(apples,plates−1)
代码:
思路2:缓存思想——动态规划来优化暴力递归
所有的暴力递归的展开过程都可以用动态规划来优化.我们想想递归是怎么解决问题的,比如遇到ways(7, 5),它是展开为ways(7,4)和ways(2,5)来解决的,然后ways(2,5)和ways(7,4)再接着展开,那如果我们之前早就计算过ways(2,5)了呢,如果已经计算过一次了,还有必要再接着展开吗?直接用上次计算的结果不就好了,这样不就可以把递归层数变浅了吗。
那么怎么记录上次计算的结果呢?这里可以用一个二维数组dp缓存存起来,并且考虑到多组输入问题,我们可以把创建二维数组dp的过程放到执行ways方法外头,这样下一组输入也可以使用我们上一轮计算过的值。
为了和0种方法区分,我们不妨先让dp的所有值都赋-1,表示尚未计算过,在递归的每一层都检查当前层中dp的是否不等于-1,如果是,说明这层没必要继续展开下去了,已经计算过了,返回 d p [ a p p l e s ] [ p l a t e s ] dp[apples][plates] dp[apples][plates],否则再执行展开过程,并且最后把这一层的计算结果记录到dp中作为缓存。
代码:
#include <vector> #include <iostream> using namespace std; int ways(int apples, int plates, vector<vector<int>>& dp) {if (dp[apples][plates] != -1){return dp[apples][plates];}int ans = 0;if (apples == 0){ans = 1;}else if (plates == 0){ans = 0;}else if (apples < plates){ans = ways(apples, apples, dp);}else{int a = ways(apples - plates, plates, dp);int b = ways(apples, plates - 1, dp);ans = a + b;}dp[apples][plates] = ans;return ans; }int main() {int apples, plates;vector<vector<int>> dp(11, vector<int>(11, -1));while (cin >> apples >> plates){cout << ways(apples, plates, dp) << endl;}return 0; }总结
以上是生活随笔为你收集整理的算法题放苹果:把M个相同的苹果放到N个完全相同的盘子里,有多少种放法?的全部内容,希望文章能够帮你解决所遇到的问题。
- 上一篇: Redis集群(windows版本操作)
- 下一篇: Jetson_TK1_TX1学习网站