伐木工(动态规划)

本文介绍了如何使用动态规划解决整数拆分问题,通过设计状态转移方程和双重for循环计算dp数组,找到最优解后,再逆向拆分以找到最少拆分数量。给出了一段Java代码示例。
摘要由CSDN通过智能技术生成

核心思路

提示:

本题本质是整数拆分的优化版,是在整数拆分后得到最优解的基础上筛选少的拆分方案。
对于选择最少的拆分方案,可以逆向将得到的最优解dp[i]进行拆分
按照:
dp[i]是当前长度为i的木头拆分得到的最大利润。
dp[i]=j*(i-j)表示长度为i的木头拆成j和i-j的最大利润。
dp[i]=dp[i-j]*j表示长度为i的木头,拆成j并接着拆dp[i-j]得到的最大利润。
三种标准进行逆向拆分,得到最少的拆分数量。

动态规划算法设计流程

动态规划算法设计:
动态规划是求dp【i】的最优解
动态规划特点是当前这一步的dp【i】最优解,是由前一步的最优解dp【i-1】得到的,有递进关系。
动态规划算法设计:
设计起点:如整数拆分,dp【2】=1作为起点
设计状态转移方程:状态转移方程:dp[i]=Math.max(dp[i],Math.max(j*(i-j),dp[i-j]*j))
设计for循环:两层for循环,i从3开始,上限是目标数。j从1开始,上限是i-1。确保从起点开始执行状态转移方程
为了确保拆分后的木材数量最少,可以在得到最优结果dp【i】后,倒序拆分dp【i】判断各个情况下的最少拆分数量,然后存入结果res链表中。

代码细节

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Scanner;

public class Main{
    public static void slice(int x,int[]dp){//动态规划函数
        for (int i = 3; i <=x; i++) {//i从3开始,确保最初i-j=2
            for (int j = 1; j < i-1; j++) {//j始终停留在i前面一个数
                dp[i]=Math.max(dp[i],Math.max(j*(i-j),j*dp[i-j]));
            }
        }
    }
    public static void main(String[] args) {
        Scanner scanner=new Scanner(System.in);
        int x=scanner.nextInt();
        int[] dp=new int[x+1];
        dp[2]=1;//初始化dp起点
        slice(x,dp);
        List<Integer> res=new ArrayList<>();
        //拆分dp【i】,寻找各个拆分情况下的最少数量
        int m=x;
        while (m>=1){
            if (dp[m]==m){
                res.add(m);//dp【i】直接等于i,不需要拆,可以直接结束while循环
                break;
            }else {
                for (int i = m-1; i >1; i--) {
                    if (dp[m]==i*(m-i)){
                        res.add(i);
                        res.add(m-i);
                        m=0;//dp【i】可直接拆成两个数,所以不再需要拆分dp【i-j】,让m=0可以结束while循环
                        break;
                    } else if (dp[m]==dp[m-i]*i) {
                        res.add(i);
                        m-=i;//为下一轮dp【m-i】的拆分做准备
                        break;
                    }
                }
            }
        }
        for (int i :
                res) {
            System.out.printf(i+" ");
        }
    }
}
  • 8
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值