问题的本质就是求将 n n n拆成 m m m份的方案数,和求 n n n个苹果放在 m m m个盘子的方案数是一个问题。
方法一:暴力dfs
#include<bits/stdc++.h>
#define FAST ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define INF 0x3f3f3f3f
typedef long long ll;
const int maxn = 1e5+5;
using namespace std;
int m,n;
int ans;
int record[maxn];
void dfs(int x, int sum, int lst)
{
if (x==n+1){
if (sum==0){
ans++;
// for (int i=1; i<=x-1; i++){
// printf("%d ",record[i]);
// }
// printf("\n");
}
return;
}
for (int i=lst; i<=sum; i++){
record[x]=i;
dfs(x+1,sum-i,i);
}
record[x]=0;
return;
}
int main()
{
// freopen("1.in","r",stdin);
// freopen("1.txt","w",stdout);
int T;
scanf("%d",&T);
while(T--){
ans=0;
scanf("%d%d",&m,&n);
dfs(1,m,0);
printf("%d\n",ans);
}
return 0;
}
方法二:二维费用背包
因为每个数可以选多次,所以这是一个完全背包
定义状态
f
[
i
]
[
j
]
[
k
]
f[i][j][k]
f[i][j][k] 表示从前
i
i
i个数中选,背包容量(数量)为
j
j
j,体积为
k
k
k的方案数
不选第
i
i
i个数:
f
[
i
]
[
j
]
[
k
]
=
f
[
i
−
1
]
[
j
]
[
k
]
f[i][j][k] = f[i - 1][j][k]
f[i][j][k]=f[i−1][j][k]
选第
i
i
i个数 :
f
[
i
]
[
j
]
[
k
]
+
=
f
[
i
]
[
j
−
1
]
[
k
−
i
]
f[i][j][k] += f[i][j - 1][k - i]
f[i][j][k]+=f[i][j−1][k−i]
方法三:动态规划
定义
f
[
i
]
[
j
]
f[i][j]
f[i][j]:将
i
i
i分为
j
j
j份的方案数
f
[
i
]
[
j
]
=
f
[
i
]
[
j
−
1
]
+
f
[
i
−
j
]
[
j
]
f[i][j]=f[i][j-1]+f[i-j][j]
f[i][j]=f[i][j−1]+f[i−j][j]