放苹果-多种题解
题目链接:https://www.nowcoder.com/practice/4f0c1e21010e4d849bde5297148e81d9?tpId=40&tqId=21372&rp=1&ru=%2Fta%2Fkaoyan&qru=%2Fta%2Fkaoyan%2Fquestion-ranking&tab=answerKey
第一种:DFS
分析:dfs函数里面遍历(搜索)什么?
我们对【当前盘子存放的苹果个数】进行遍历(从【上一个盘子存放的苹果个数】到【总苹果个数】)。
继续分析:为啥【当前盘子存放苹果个数】遍历的起始值为【上一个盘子存放的苹果个数】?
因为题目原句"5,1,1和1,5,1 是同一种分法",所以我们搜索时如果没有order的话,会重复计数。
因此,我们让【当前盘子存放苹果个数】>=【上一个盘子存放的苹果个数】。
分析:dfs(int sum_m,int n,int now_m)的含义?
sum_m表示当前苹果总数,n表示盘子数,now_m表示当前盘子存放的苹果数目。
对本题用dfs,【搜索的对象】其实就是【每一个盘子可以存放的苹果个数】,去搜索【每一种存放情况】,然后判断是否为本题需要的情况(盘子数不大于N,苹果数等于M)。
代码:
1 #include<iostream> 2 using namespace std; 3 int N,M; 4 int count; 5 void dfs(int sum_m,int n,int now_m){//sum_m表示当前苹果总数,n表示盘子数,now_m表示当前盘子存放的苹果数目 6 if(sum_m>=M){//递归结束条件 7 if((sum_m==M)&&(n<=N)) count++; 8 return ; 9 } 10 for(int i=now_m;i<=M;i++){ 11 dfs(sum_m+i,n+1,i); 12 } 13 } 14 int main(){ 15 cin>>M>>N; 16 count=0; 17 dfs(0,0,1); 18 cout<<count<<endl; 19 }
第二种:动态规划
分析状态转移方程:
dp[i][j]:i是苹果数目,j是盘子数目,dp[i][j]表示i个苹果放到j个盘子分发的种数。
研究对象:是否有盘子空着(两种情况,至少有一个盘子空着与所有盘子都被使用这两种情况)。
当i<j,即盘子数 > 苹果数,dp[i][j]=dp[i][j-1]
解释:对于盘子数 > 苹果数,可知一定会有盘子空着,因为盘子最多只会用到i个,而对于j>i而言,j与j-1都大于等于i,多一个盘子对于分发种数是不变的)。
当i=j,即盘子数 = 苹果数,dp[i][j]=dp[i][j-1]+1
解释:对于盘子数 = 苹果数,我们可以分为两种情况:至少有一个盘子空着与所有盘子都被使用这两种情况。
至少有一个盘子空着:不使用第j个盘子即可保证本情况,也即dp[i][j-1]。
所有盘子都被使用:因为盘子数 = 苹果数,所以只有一种情况,即每个盘子放一个苹果。
当i>j,即盘子数 < 苹果数,dp[i][j] = dp[i-j][j] + dp[i][j-1]
解释:对于盘子数 < 苹果数,我们可以分为两种情况:至少有一个盘子空着与所有盘子都被使用这两种情况。
至少有一个盘子空着:不使用第j个盘子即可保证本情况,也即dp[i][j-1]。
所有盘子都被使用:j个盘子都被使用,则说明至少j个苹果被使用,还剩i-j个苹果,这些苹果再放到j个盘子,也即dp[i-j][j]。
代码:
1 #include<iostream> 2 using namespace std; 3 int dp[11][11];//i表示苹果个数,j表示盘子个数 4 int main(){ 5 int m,n;//m个苹果,n个盘子 6 cin>>m>>n; 7 for(int i=1;i<=m;i++){ 8 dp[i][1]=1; 9 for(int j=2;j<=n;j++){ 10 if(i<j) dp[i][j]=dp[i][j-1]; 11 else if(i==j) dp[i][j]=dp[i][j-1]+1; 12 else dp[i][j]=dp[i][j-1]+dp[i-j][j]; 13 } 14 } 15 cout<<dp[m][n]; 16 return 0; 17 }

浙公网安备 33010602011771号