放苹果
把M个同样的苹果放在N个同样的盘子里,允许有的盘子空着不放,问共有多少种不同的分法?(用K表示)5,1,1和1,5,1 是同一种分法。
Input
第一行是测试数据的数目t(0 <= t <= 20)。以下每行均包含二个整数M和N,以空格分开。1<=M,N<=10。
Output
对输入的每组数据M和N,用一行输出相应的K。
Sample Input
1
7 3
Sample Output
8
做法一:dfs枚举
因为不能有重复的情况,那么就从小到大进行枚举,每次选的数字要大于等于上一次选的数字
#include <iostream>
using namespace std;
int res;
// 上次使用的数字,剩余的数字,剩余盘子
void dfs(int past, int num, int cnt)
{
if (cnt == 1) {
res++;
return;
}
for (int i = past; i <= num / cnt; i++) {
dfs(i, num - i, cnt - 1);
}
}
int main(void)
{
int t, m, n;
cin >> t;
while (t--) {
res = 0;
cin >> m >> n;
dfs(0, m, n);
cout << res << endl;
}
return 0;
}
做法二:递归
1、边界情况:苹果数为0或者盘子数为1时,f(m, n) = 1
2、m<n时,至少有n-m个盘子会空着,有f(m, n) = f(m, m)
3、m>=n,有两种情况:
①至少有一个盘子没有放苹果,有f(m, n - 1)
②所有盘子都放了苹果,从每个盘子里都拿走一个苹果,有f(m - n, n)
由①②可知,f(m, n) = f(m, n - 1) + f(m - n, n)
yfy同学的代码
#include <iostream>
using namespace std;
int f(int m, int n)
{
if (m == 0 || n == 1)
return 1;
if (m < n)
return f(m, m);
else
return f(m, n - 1) + f(m - n, n);
}
int main(void)
{
int t;
int m, n, res;
cin >> t;
for (int i = 0; i < t; i++) {
cin >> m >> n;
res = f(m, n);
cout << res << endl;
}
return 0;
}
数字划分
链接:https://ac.nowcoder.com/acm/problem/16695
来源:牛客网
题目描述
将整数n分成k份,且每份不能为空,任意两个方案不能相同(不考虑顺序)。
例如:n=7,k=3,下面三种分法被认为是相同的。
1,1,5;
1,5,1;
5,1,1;
问有多少种不同的分法。
输入:n,k ( 6 < n ≤ 200,2 ≤ k ≤ 6 )
输出:一个整数,即不同的分法。
输入描述:
两个整数 n,k ( 6 < n ≤ 200, 2 ≤ k ≤ 6 )
输出描述:
1个整数,即不同的分法。
输入
7 3
输出
4
和上面的题类似,不同的是每份不能为空,那么就从1开始枚举
#include <iostream>
using namespace std;
int res;
// 上一次使用的数字,剩余的数字,剩余的盘子
void dfs(int past, int num, int cnt)
{
if (cnt == 1){
res++;
return;
}
for (int i = past; i <= num / cnt; i++)
dfs(i, num - i, cnt - 1);
}
int main(void)
{
int n, k;
cin >> n >> k;
dfs(1, n, k);
cout << res << endl;
return 0;
}
dp做法
代码转载自:https://ac.nowcoder.com/acm/contest/view-submission?submissionId=44262528
#include <iostream>
#include <cstdio>
#include <algorithm>
int f[205][10];
using namespace std;
int main()
{
int n,k;
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)
{
f[i][1]=1; //将i划分成1份肯定只有一种
f[i][0]=1; //将i划分成0份肯定不存在
}
for(int i=2;i<=k;i++)
{
f[1][i]=0; //将1划分成i份(i>1)肯定不存在
f[0][i]=0; //将0划分成i份(i>1)肯定不存在
}
for(int i=2;i<=n;i++)
{
for(int j=2;j<=k;j++)
{
if(i>j)
f[i][j]=f[i-1][j-1]+f[i-j][j];
else //i<=j的情况
f[i][j]=f[i-1][j-1];
}
}
printf("%d",f[n][k]);
return 0;
}