分月饼--动态规划--Java

题目

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

说明

4=1+3

4=2+2

注意:1+3和3+1要算成同一种分法

示例2:

输入

3 5

输出

2

说明

5=1+1+3

5=1+2+3

示例3:

输入

3 12

输出

6

说明

满足要求的6种分法:

1、12 = 1 + 1 + 10 (Max1=10, Max2=1,不满足Max1-Max2 <= 3的约束)

2、12 = 1 + 2 + 9 (Max1=9,Max2=2,不满足Max1-Max2 <= 3的约束)

3、12 = 1 + 3 + 8 (Max1=8,Max2=3,不满足Max1-Max2 <= 3的约束)

4、12 = 1 + 4 + 7 (Max1=7,Max2=4,Max3=1, 满足要求)

5、12 = 1 + 5 + 6 (Max1=6,Max2=5,Max3=1, 不满足要求)

6、12 = 2 + 2 + 8 (Max1=8,Max2=2,不满足要求)

7、12 = 2 + 3 + 7 (Max1=7,Max2=3,不满足要求)

8、12 = 2 + 4 + 6 (Max1=6,Max2=4,Max3=2, 满足要求)

9、12 = 2 + 5 + 5 (Max1=5,Max2=2 满足要求)

10、12 = 3 + 3 + 6 (Max1=6,Max2=3 满足要求)

11、12 = 3 + 4 + 5 (Max1=5,Max2=4,Max3=3 满足要求)

12 = 4 + 4 + 4 (Max1=4,满足要求)

思路

动态规划做法

1.状态表示

dp[i][j][k]:前i个人已经分了j个月饼,且第i个人分到了k个月饼。(1<=i<=m,i<=j<=n,1<=k<j)

2.初始值

dp[1][k][k]=1:第一个人分到k个月饼的方案数为1。(1<=k<=n)

3.转态转移方程

这题方案数的计算方式是不同数字的组合方式,不考虑数字的顺序,因此我们直接按照从小到大来分月饼即可,即找到一个不严格单调递增的正整数数列。

dp[i][j][k]+=dp[i-1][j-k][l];前i个人已经分了j个月饼且第i个人分到了k个月饼的方案数=前i-1个人已经分了j-k个月饼且第i-1个人分到了l个月饼的方案数总和。( l ∈[max(k-3,1),k],只考虑第i-1个人分到的月饼数比第i人分到的月饼数相差不超过3的方案)

4.答案

ans=dp[m][n][1]+dp[m][n][2]+...+dp[m][n][n]

代码

import java.util.Scanner;

/**
 * @author jn
 * @version 1.0
 * @description: TODO
 * @date 29/6/2024 下午5:20
 */
public class DivideMooncake {

    public static void main(String[] args) {
        Scanner scan=new Scanner(System.in);
        int m=scan.nextInt();//员工
        int n=scan.nextInt();//月饼
        int[][][] dp=new int[m+1][n+1][n+1];
        //dp[i][j][k]
        for (int k = 1; k <=n; k++) {
            dp[1][k][k]=1;
        }

        for (int i = 1; i <=m; i++) {
            for (int j = i; j <=n ; j++) {
                for (int k = 1; k < j; k++) {
                    for (int l = Math.max(k-3,1); l<=k; l++) {
                        dp[i][j][k]+=dp[i-1][j-k][l];
                    }
                }
            }
        }

        int ans=0;
        for (int i = 1; i <=n; i++) {
            ans+=dp[m][n][i];
        }
        System.out.println(ans);
    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值