在解这道题之前,我们先看一道跟这道题很像的题目:
把m个同样的苹果放在n个同样的盘子里,允许有的盘子空着不放,问有多少种不同的分法?(注:5,1,1和1,1,5是同一种分法)
问题分析:
f(m,n): 表示把m个苹果,放入n个盘子的分配方法总数
1.当m = 0或 n = 1时,只有一种分法
2.当m < n 时,即当苹果数少,盘子过剩时。此时一定有n-m个盘子一直空着,去掉他们对于分配的总数没有影响。
if(m < n) f(m,n) = f(m,m);
3.当 m >= n 时,不同的放法可以分为两类:1.含0的方案数 2.不含0的方案数
- 含0的方案数:即至少有一个盘子空着,此时f(m,n) = f(m,n-1)
- 不含0的方案:即所有盘子都有苹果,相当于可以从每个盘子中拿掉一个苹果,不影响不同放法的数目,即f(m,n) = f(m-n,n)
综上,if(m >= n) f(m,n) = f(m,n-1)+f(m-n,n)
下面是详细代码:
import java.util.*;
public class Main{
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int m = sc.nextInt(); //苹果数
int n = sc.nextInt(); //盘子数
System.out.println(func(m,n));
}
private static int func(int i,int j) {
if(i == 0 || j == 1) {
return 1;
}
if(i < j) {
return func(i,i);
}
else {
return func(i,j-1)+func(i-j,j);
}
}
}
下面我们分析上面的题目:
划分数的题目的思路跟分苹果的思路差不多,下面我们采用动态规划的解法
dp[i][j]: j的i划分
递推公式:
import java.util.*;
public class Main{
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt(); //物品
int m = sc.nextInt(); //组数
int M = sc.nextInt();
int[][] dp = new int[10001][10001];
dp[0][0] = 1;
for(int i = 1;i <= m;i++) {
for(int j = 0;j <= n;j++) {
if(j>= i) {
dp[i][j] = (dp[i-1][j]+dp[i][j-i])%M;
}
else {
dp[i][j] = dp[i-1][j];
}
}
}
System.out.println(dp[m][n]);
}
}