动态规划问题(一)最大切分段数

问题描述

​ 给你一段长为 L 的木棒,现在有三种切分长度 p、q、r,你只能将这根木棒切成在这三种长度内的组合,求这根木棒最大能够切成多少段。

​ 比如说:现在一根长为 11 的木棒,可以切分的长度为 2、3、5,因此该木棒最多能够被切成 5 段,分别是:{2、2、2、2、3}

解决思路

​ 由于只能在候选的三个长度内进行组合,因此可以考虑将这根木棒递归地按照候选长度进行切分,然后得到最终的组合数。然而,在这里使用递推地方式可能会更好一些。

​ 解决方案:在每个长度位置检测是否能够加上对应的候选长度,如果能加上,那么就是能切分的段数加一,但是可能也会有其它的方案可以组合目标长度,因此需要对比得到最大值。

​ 状态转换方程:

\[f(n) = max(f(n - p), f(n - q), f(n - r)) + 1 \]

​ 边界分析:对于长度为 0 的木棒,不存在相对应的切分方法,因此它的组合数为 0。

实现

public class Solution {
    /**
     * 得到长度为 n 的木棒能够按照候选的长度组合的最大元素个数
     *
     * @param n : 木棒的长度
     * @param x : 可切成的候选长度 p
     * @param y : 可切成的候选长度 q
     * @param z : 可切成的候选长度 r
     * @return : 能够切分的最大段数
     */
    public static int maximizeCuts(int n, int x, int y, int z) {
        int[] dp = new int[n + 1];

        // 由于有的长度是无法在当前的候选长度集合中进行切分的,因此需要考虑跳过它
        for (int i = 1; i <= n; ++i)
            dp[i] = -1;

        // 边界情况,长度为 0 的木棒对任何候选切分子集切分的段数都为 0
        dp[0] = 0;

        for (int i = 0; i <= n; ++i) {
            // 如果当前访问的长度是无法由现有的组合子集组合,那那么就说明不能被切分,跳过它
            if (dp[i] == -1) continue;

            /*
                如果当前的长度加上备选的切割长度要小于总共的木棒长度,
                那么就可以将组个分割的子段长度加到现有的长度上,同时增加段数
                由于加上的长度结果可能由多种组合情况,因此要找到最大的组合段数
            */
            if (i + x <= n)
                dp[i + x] = Math.max(dp[i + x], dp[i] + 1);
            if (i + y <= n)
                dp[i + y] = Math.max(dp[i + y], dp[i] + 1);
            if (i + z <= n)
                dp[i + z] = Math.max(dp[i + z], dp[i] + 1);
        }

        // 如果目标段数不能由现有的组合段数组合而来,则返回 0
        if (dp[n] == -1) return 0;

        return dp[n];
    }
}
posted @ 2021-08-12 14:06  FatalFlower  阅读(299)  评论(0编辑  收藏  举报