题目连接:http://ybt.ssoier.cn:8088/problem_show.php?pid=1192

一递归方式:视频讲解地址:https://www.bilibili.com/video/av27747114/?p=12

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int m,n;
 4 int up(int m,int n)
 5 {
 6     if(m==0||n==1)return 1;
 7     if(m<n)return up(m,m);
 8     else return up(m,n-1)+up(m-n,n);
 9 }
10 int main()
11 {
12     int s;
13     cin>>s;
14     while(s--)
15     {
16         cin>>m>>n;
17         cout<<up(m,n)<<endl;
18     }
19     return 0;
20 }

二递推(简单动态规划),从某种意义讲递推和动归很难区分

 1 #include<iostream>
 2 #include<cstring>
 3 using namespace std;
 4 int a[20][20];//状态:a[m][n]表示m个苹果放在n个盘子里的方法数
 5 int f(int m,int n)
 6 {
 7     int i,j;
 8     for(i=1;i<=n;i++)//0个苹果
 9         a[0][i]=1;
10     for(i=1;i<=m;i++)//1个盘子
11         a[i][1]=1;
12     for(i=1;i<=m;i++)
13         for(j=2;j<=n;j++)
14             if(i<j)
15                 a[i][j]=a[i][i];
16             else
17                 a[i][j]=a[i][j-1]+a[i-j][j]; //状态转移方程
18 }
19 int main()
20 {
21     int m,n,i,j,k;
22     cin>>k;
23     for(i=1;i<=k;i++)
24     {
25         cin>>m>>n;
26         f(m,n);
27         cout<<a[m][n]<<endl;
28     }
29     return 0;
30 }

三、其他博客方法总结(摘自https://blog.csdn.net/QiaoRuoZhuo/article/details/80583072

  1 /*
  2     Name: 放苹果问题集锦(每个盘子至少放1个苹果)
  3     Copyright:
  4     Author:
  5     Date: 31-07-17 21:22
  6     Description: 放苹果
  7 查看 提交 统计 提问
  8 总时间限制: 1000ms 内存限制: 65536kB
  9 描述
 10 把N个同样的苹果放在M个同样的盘子里,允许有的盘子空着不放,问共有多少种不同的分法?(用K表示)5,1,1和1,5,1 是同一种分法。
 11 输入
 12 第一行是测试数据的数目t(0 <= t <= 20)。以下每行均包含二个整数M和N,以空格分开。1<=M,N<=10。
 13 输出
 14 对输入的每组数据N和M,用一行输出相应的K。
 15 样例输入
 16 1
 17 7 3
 18 样例输出
 19 4
 20 算法思路:
 21 回溯算法:有2种思路,一种是确保后面的盘子中苹果不比前面的少,另一种是确保后面的盘子中苹果不比前面的多。
 22 第2种思路递归深度较少,但代码复杂些,特别要注意第n个盘子能放苹果的数量范围。
 23 基本上递归问题都可以转化为记忆化搜索,然后转换为动态规划问题。
 24 回溯算法相当于穷举,不但可以获得组合的数量,还可以存储具体的解空间。
 25 记忆化搜索和动态规划算法均采用了确保后面的盘子中苹果不比前面的多的思路;其中动态规划进行了降维优化。
 26 每个盘子至少放1个苹果和每个盘子至少放0个苹果的递归表达式以及边界条件都不一样。
 27 */
 28 #include<iostream>
 29
 30 using namespace std;
 31
 32 const int MAXN = 10; //苹果的最大数量 
 33 const int MAXM = 10; //盘子的最大个数
 34 int A1[MAXN+1], A2[MAXN+1];
 35 int M, N, s1, s2;
 36 long long B[MAXM+1][MAXN+1]; //记录给定n个盘子装m个苹果的方案总数 
 37 long long B2[MAXM+1][MAXN+1]; //记录给定n个盘子装m个苹果的方案总数 
 38 long long pre[MAXN+1]; //记录给定n个盘子装m个苹果的方案总数 
 39 long long cur[MAXN+1]; //记录给定n个盘子装m个苹果的方案总数 
 40 long long F[MAXN+1]; //记录给定n个盘子装m个苹果的方案总数 
 41
 42 void DFS_1(int k, int n); //n表示共n个苹果,k表示第k个盘子   
 43 void DFS_2(int k, int n); //n表示共n个苹果,k表示第k个盘子
 44 long long Fun(int k, int n); //记忆化搜索
 45 void Fun2(int k, int n); //动态规划:使用二维数组 
 46 long long Fun3(int k, int n); //动态规划:使用2个一维数组 
 47 long long Fun4(int k, int n); //动态规划:使用1个一维数组 
 48
 49 int main()
 50 {
 51     int t;
 52
 53     Fun2(MAXM, MAXN);
 54     cin >> t;
 55     for (int k=0; k<t; k++)
 56     {
 57         cin >> N >> M;
 58
 59         s1 = 0;
 60         DFS_1(1, N);
 61         cout << s1 << endl;
 62
 63         s2 = 0;
 64         int minNum = N/M + (N%M!=0);
 65         for (A2[1]=N-M+1; A2[1]>=minNum; A2[1]--)//第一个盘中放A2[1]个苹果     
 66         {
 67             DFS_2(2, N-A2[1]);
 68         }
 69         cout << s2 << endl;
 70
 71         cout << Fun(M, N) << endl;
 72         cout << B2[M][N] << endl;
 73         cout << Fun3(M, N) << endl;
 74     }
 75
 76     return 0;
 77 }
 78
 79 void DFS_1(int k, int n) //n表示共n个苹果,k表示第k个盘子       
 80 {
 81     if (k == M)//最后一个盘子      
 82     {
 83         A1[k] = n;
 84         cout << s1 << " : ";
 85         for (int i=1; i<=k; i++)
 86             cout << A1[i] << " ";
 87         cout << endl;
 88         s1++;
 89     }
 90     else  //至少还有2个盘子    
 91     {
 92         for (A1[k]=max(1,A1[k-1]); A1[k]+A1[k]<=n; A1[k]++)
 93         {   //确保剩下的苹果不比当前盘子中的少       
 94             DFS_1(k+1, n-A1[k]);
 95         }
 96     }
 97 }
 98
 99 void DFS_2(int k, int n) //n表示共n个苹果,k表示第k个盘子   
100 {
101     if (n <= 0)
102         return;
103
104     if (k == M)//最后一个盘子 
105     {
106         if (n > A2[k-1]) //确保后面的盘子中苹果不比前面的多  
107             return;
108         A2[k] = n;
109         cout << s2 << " : ";
110         for (int i=1; i<=k; i++)
111             cout << A2[i] << " ";
112         cout << endl;
113         s2++;
114     }
115     else
116     {
117         int maxNum = min(n, A2[k-1]);//确保后面的盘子中苹果不比前面的多 
118         for (A2[k]=maxNum; A2[k]>=1; A2[k]--)
119         {
120             DFS_2(k+1, n-A2[k]);
121         }
122     }
123 }
124
125 long long Fun(int k, int n) //记忆化搜索
126 {
127     if (B[k][n] != 0)
128         return B[k][n];
129     if (k == 1 || n == k)//只有1个盘子或者盘子与苹果数量相等 
130         B[k][n] = 1;
131     else if (n < k) //苹果数量少于盘子 
132         B[k][n] = 0;
133     else //两种情况:第k个盘子只放一个苹果;每个盘子至少放2个苹果,则每个盘子中拿走1个苹果后,分配方法数量不变 
134         B[k][n] = Fun(k-1, n-1) + Fun(k, n-k);
135
136     return B[k][n];
137 }
138
139 void Fun2(int k, int n) //动态规划:使用二维数组 
140 {
141     for (int j=1; j<=n; j++)//j个苹果放到1个盘子里 
142         B2[1][j] = 1;
143     for (int i=2; i<=k; i++)
144     {
145         for (int j=i; j<=n; j++)
146         {
147             B2[i][j] = B2[i-1][j-1] + B2[i][j-i];
148         }
149     }
150 }
151
152 long long Fun3(int k, int n) //动态规划:使用2个一维数组 
153 {
154     for (int j=1; j<=n; j++)//j个苹果放到1个盘子里 
155         pre[j] = 1;
156     for (int i=2; i<=k; i++)
157     {
158         for (int j=1; j<i; j++) //苹果数量少于盘子 
159         {
160             cur[j] = 0;
161         }
162         for (int j=i; j<=n; j++)
163         {
164             cur[j] = pre[j-1] + cur[j-i];
165         }
166         for (int j=1; j<=n; j++)
167         {
168             pre[j] = cur[j];
169         }
170     }
171
172     return pre[n];
173 }
03-31 02:48