一、题目描述
中秋节,公司分月饼,m 个员工,买了 n 个月饼,m<=n,每个员工至少分 1 个月饼,但可以分多个,单人分到最多月饼的个数为 Max1,单人分到第二多月饼的个数是 Max2,Max1-Max2<=3,单人分到第 n-1 多月饼个数是 Max(n-1),单人分到第 n 多月饼的个数是 Max(n),Max(n-1)-Max(n)<=3。请问有多少种分月饼的方法?
**输入描述**
每一行输入 m、n,表示 m 个员工,n 个月饼,m<=n
**输出描述**
输出有多少种分月饼的方法
**示例 1**
输入
2 4
输出
2
-------------------------------------------------------------------------------------------------------------------
> 说明
> 分法有 2 种:
> 4 = 1 + 3
> 4 = 2 + 2
> 注意:1+3 和 3+1 算一种分法
**示例 2**
输入
3 5
输出
2
-------------------------------------------------------------------------------------------------------------------
> 说明
> 分法有 2 种:
> 5 = 1 + 1 + 3
> 5 = 1 + 2 + 2
**示例 3**
输入
3 12
输出
6
-------------------------------------------------------------------------------------------------------------------
> 说明
> 满足要求的有 6 种分法:
> 12 = 1 + 1 + 10(Max1=10,Max2=1,不满足要求)
> 12 = 1 + 2 + 9(Max1=9,Max2=2,不满足要求)
> 12 = 1 + 3 + 8(Max1=8,Max2=3,不满足要求)
> 12 = 1 + 4 + 7(Max1=7,Max2=4,Max3=1,满足要求)
> 12 = 1 + 5 + 6(Max1=6,Max2=5,Max3=1,不满足要求)
> 12 = 2 + 2 + 8(Max1=8,Max2=2,不满足要求)
> 12 = 2 + 3 + 7(Max1=7,Max2=3,不满足要求)
> 12 = 2 + 4 + 6(Max1=6,Max2=4,Max3=2,满足要求)
> 12 = 2 + 5 + 5(Max1=5,Max2=5,Max3=2,满足要求)
> 12 = 3 + 3 + 6(Max1=6,Max2=3,Max3=3,满足要求)
> 12 = 3 + 4 + 5(Max1=5,Max2=4,Max3=3,满足要求)
> 12 = 4 + 4 + 4(Max1=4,Max2=4,Max3=4,满足要求)
二、解题思路
1. m 个人有 n 个月饼,先将 m 个人每个人分一个,剩余总月饼数为 n-m=p;
2. 假设第一个人最少分 k 个,第二个人范围就是[k, k+3],Max(n-1)-Max(n)<=3。
3. 当 m 为 3 个人时情况如下:
4. 我们假设第一个人总是分到最少的,第二个人分到第二少的,依次类推;
第一个人最少分 0 个(n-m 后的 p,就是给每位各分了一个后剩余的月饼数),剩下两个人有 n-3(p)个月饼可分,此时,如果第二个人分 k 个,第三个人就是 n-3-k(p-k)个,满足 k<=p-k <= k+3(第三个人比第二个人的只多 0-3 个);
5. 依次循环类推,如果第一个人分 1 个,剩下两个人分 n-3-1 个,循环逻辑一致; 6.同理,如果是四个人时,分为第一个人和后三个人,后三个人又分为第一个人和后两个人,第一个人总是分最少的,第二个比他多 0-3 个,依次类推,我们发现这是一个递归调用过程。代码需要有一个递归函数 distribute,给他下一个数量,并让他完成递归判断。当然对于两个人的情况,我们单独判断即可。
三、代码实现
public int getMoonCake(int m, int n) {
if (m > n) {
return 0;
}
int p = n - m;
int count = 0;
for (int i = 0; i < p; i++) {
count = count + distribute(m - 1, p - i, i);
}
System.out.println(count);
return count;
}
private int distribute(int m, int p, int k) {
if (p <= 0) return 0;
if (m <= 0) return 0;
if (m == 1) {
if (p >= k && p <= k + 3) {
return 1;
}
return 0;
}
int ncount = 0;
for (int knext = k; knext <= k + 3; knext++) {
ncount = ncount + distribute(m - 1, p - knext, knext);
}
return ncount;
}
四、测试验证
@Test
void getMoonCake() {
Assertions.assertEquals(2, day02.getMoonCake(2, 4));
Assertions.assertEquals(2, day02.getMoonCake(3, 5));
Assertions.assertEquals(6, day02.getMoonCake(3, 12));
}