【OD真题】分月饼[200 分]

该篇文章介绍了一种计算在公司分月饼问题中,满足特定条件(单人分得的月饼数差不超过3个)的分法数量的算法,使用了递归方法。通过示例和代码实现展示了如何通过递归函数`distribute`来计算不同员工人数和月饼数量下的分法总数。
摘要由CSDN通过智能技术生成

一、题目描述

中秋节,公司分月饼,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));
    }

  • 0
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值