伐木工 - 华为OD统一考试

OD统一考试

题解: Java / Python / C++

题目描述

一根X米长的树木,伐木工切割成不同长度的木材后进行交易,交易价格为每根木头长度的乘积。规定切割后的每根木头长度都为正整数,也可以不切割,直接拿整根树木进行交易。请问伐木工如何尽量少的切割,才能使收益最大化?

输入描述

木材的长度(X<=50)

输出描述

输出最优收益时的各个树木长度,以空格分割,按升序排列

示例1

复制代码
输入:
10

输出:
3 3 4

说明:
1.一根2米长的树木,伐木工不切割,为2*1,收益最大为2
2.一根4米长的树木,伐木工不需要切割为2*2,省去切割成本,直接整根树木交易,为4*1,收益最大为4
3.一根5米长的树木,伐木工切割为2*3,收益最大为 6
4.一根10米长的树木,伐木工可以切割为方式: 3,4,3,也可以切割为方式二:3,2,2,3,但方式二代木工多切割了一次增加切割成本却卖了一样的价格,因此并不是最优收益。

题解

动态规划类型的问题。

通过动态规划的方法:

1、定义一个状态数组 dp,其中 dp[x] 表示长度为 x 的树木的最大化收益。

2、定义一个数组 d ,其中 d[x] 用于记录长度为 x 的树木达到最大收益时,最后一节的长度(收益相同取切割次数最少的)。

3、定义 times , 其中 times[x] 数组表示长度为x的树木最小需要切割的次数。

动态规划的状态转移方程为:dp[x]=max⁡(dp[x],dp[j]×(x−j)), for j∈[1,x−1]

这表示尝试对长度为 x 的树木进行切割,寻找使收益最大的切割方式。

最后,我们通过回溯 d 数组,获取切割的具体方式,并按升序排列输出。

代码中,使用了两个数组 dpd 分别表示最大收益和最后一节的长度,遍历计算得到最优解。时间复杂度为 O(X^2),其中 X 为树木的长度。空间复杂度为 O(X)。

Java

java 复制代码
import java.util.ArrayList;
import java.util.Collections;
import java.util.Scanner;
/**
 * @author code5bug
 */
public class Main {

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int x = scanner.nextInt();

        // dp[x] 表示长度为 x 的树木最大化的收益
        int[] dp = new int[x + 1];
        // times[x]使长度为 x 的树木最大化的收益,最小需要切割的次数
        int[] times = new int[x + 1];
        // d[x] 表示长度为 x 的树木要达到最大收益最后一节的长度
        int[] d = new int[x + 1];

        for (int i = 1; i <= x; i++) {
            // 不切割时的收益
            dp[i] = d[i] = i;

            // 尝试对长度为 i 的树木进行切割以获取最大收益
            for (int j = 1; j < i; j++) {
                if (dp[i - j] * j > dp[i]) { //  切割出长度 j 的一段,判断是否能收益变大
                    d[i] = j;
                    dp[i] = dp[i - j] * j;
                    times[i] = times[i - j] + 1;
                } else if (dp[i - j] * j == dp[i] && times[i] > times[i - j] + 1) { // 收益相同但切割次数少
                    d[i] = j;
                    times[i] = times[i - j] + 1;
                }
            }
        }

        int idx = x;
        ArrayList<Integer> rs = new ArrayList<>();
        while (idx > 0) {
            rs.add(d[idx]);
            idx -= d[idx];
        }

        Collections.sort(rs);
        for (int i : rs) {
            System.out.print(i + " ");
        }
    }
}

Python

python 复制代码
x = int(input())

# dp[x] 表示长度为 x 的树木最大化的收益
dp = [i for i in range(x + 1)]
# 使长度为 x 的树木最大化的收益,最小需要切割的次数
times = [0] * (x + 1)
# d[x] 表示长度为 x 的树木要达到最大收益最后一节的长度
d = [i for i in range(x + 1)]

for i in range(1, x + 1):
    for j in range(1, i):  # 尝试对长度为 i 的树木进行切割以获取最大收益
        if dp[i - j] * j > dp[i]:  # 切割出长度 j 的一段,判断是否能收益变大
            d[i] = j
            dp[i] = dp[i-j] * j
            times[i] = times[i-j] + 1
        elif dp[i-j] * j == dp[i] and times[i] > times[i-j] + 1:  # 收益相同但切割次数少
            d[i] = j
            dp[i] = dp[i-j] * j
            times[i] = times[i - j] + 1

idx, rs = x, []
while idx > 0:
    rs.append(d[idx])
    idx -= d[idx]

rs.sort()
print(*rs)

C++

cpp 复制代码
#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

int main() {
    int x;
    cin >> x;

    // dp[x] 表示长度为 x 的树木最大化的收益
    vector<int> dp(x + 1);
    // times[x] 使长度为 x 的树木最大化的收益,最小需要切割的次数
    vector<int> times(x + 1);
    // d[x] 表示长度为 x 的树木要达到最大收益最后一节的长度
    vector<int> d(x + 1);

    for (int i = 1; i <= x; i++) {
        // 不切割时的收益
        dp[i] = d[i] = i;

        // 尝试对长度为 i 的树木进行切割以获取最大收益
        for (int j = 1; j < i; j++) {
            if (dp[i - j] * j > dp[i]) { // 切割出长度 j 的一段,判断是否能收益变大
                d[i] = j;
                dp[i] = dp[i - j] * j;
                times[i] = times[i - j] + 1;
            } else if (dp[i - j] * j == dp[i] && times[i] > times[i - j] + 1) { // 收益相同但切割次数少
                d[i] = j;
                times[i] = times[i - j] + 1;
            }
        }
    }

    int idx = x;
    vector<int> rs;
    while (idx > 0) {
        rs.push_back(d[idx]);
        idx -= d[idx];
    }

    sort(rs.begin(), rs.end());

    for (int i : rs) {
        cout << i << " ";
    }

    return 0;
}

🙏整理题解不易, 如果有帮助到您,请给点个赞 ‍❤️‍ 和收藏 ⭐,让更多的人看到。🙏🙏🙏

相关推荐
不要再敲了4 小时前
JDBC从入门到面试:全面掌握Java数据库连接技术
java·数据库·面试
西猫雷婶4 小时前
pytorch基本运算-Python控制流梯度运算
人工智能·pytorch·python·深度学习·神经网络·机器学习
潇I洒5 小时前
若依4.8.1打包war后在Tomcat无法运行,404报错的一个解决方法
java·tomcat·ruoyi·若依·404
子午5 小时前
Python的uv包管理工具使用
开发语言·python·uv
kyle~5 小时前
排序---插入排序(Insertion Sort)
c语言·数据结构·c++·算法·排序算法
java1234_小锋5 小时前
Scikit-learn Python机器学习 - 分类算法 - 朴素贝叶斯
python·机器学习·scikit-learn
凡梦千华5 小时前
Django时区感知
后端·python·django
Funcy5 小时前
XxlJob 源码分析05:执行器注册流程
java
Boop_wu5 小时前
[数据结构] 队列 (Queue)
java·jvm·算法
无敌的神原秋人5 小时前
关于Redis不同序列化压缩性能的对比
java·redis·缓存