贪心算法之船舶装载问题

一、问题引入

船舶装载问题是经典的贪心算法应用场景,核心目标是:在给定船舶最大载重量的限制下,计算出最多能装载的物品数量。该问题的关键在于如何选择物品装载顺序,以实现 "数量最多" 的目标,而贪心算法通过 "每次选最优" 的策略高效解决此问题。

二、贪心算法原理

1. 核心思路

贪心算法的核心思想是 "局部最优 → 全局最优"。针对船舶装载问题,"局部最优" 即每次选择当前剩余物品中重量最轻的物品进行装载,因为选择轻的物品能最大限度地节省载重量空间,从而为后续装载更多物品创造条件,最终实现 "装载数量最多" 的全局最优目标。

2. 算法步骤

  1. 输入物品数量、船舶最大载重量以及每个物品的重量。
  2. 将所有物品按重量升序排序(关键步骤,为 "选最轻" 提供基础)。
  3. 从排序后的物品中,依次选取物品并累加重量,直到累加重量超过最大载重量为止。
  4. 统计并返回已装载的物品数量

三、代码结构与优化分析

1. 原始代码核心逻辑

原始代码通过 main 函数完成输入、排序调用和结果计算,maxLoad 函数实现装载数量统计,但存在可读性差、安全性低等问题,具体表现为:

  1. 输入提示与计算逻辑混杂在main函数中,代码冗余。

  2. 使用原始数组存储物品重量,存在固定大小限制,灵活性不足。

  3. 缺乏输入验证,若用户输入非法值(如负数、非数字),程序可能崩溃。

2. 优化后代码解析

优化后的代码基于 C++ 实现,解决了原始代码的缺陷,结构更清晰、安全性更高,具体代码及核心模块分析如下:

(1)头文件依赖
cpp 复制代码
#include <iostream> // 输入输出流
#include <algorithm> // 包含sort排序函数
#include <vector> // 动态数组,替代原始数组
using namespace std;
(2)核心函数 1:maxLoad(计算最大装载数量)
cpp 复制代码
int maxLoad(const vector<double>& weights, double capacity) {
    double total = 0.0; // 已装载物品总重量
    int count = 0; // 已装载物品数量
    // 遍历排序后的物品(范围for循环,C++11及以上特性)
    for (const auto& weight : weights) {
        if (total + weight <= capacity) { // 若能装下当前物品
            total += weight;
            ++count;
        } 
        else {
            break; // 超过载重量,停止装载
        }
    }
    return count;
}

关键优化点

  • 用vector<double>替代原始数组:动态调整大小,避免固定长度限制,提高灵活性。
  • const修饰符:确保weights数组在函数内不被修改,提升代码安全性。
  • 引用传递(& weights):避免数组拷贝,提高程序运行效率。
(3)核心函数 2:inputWeights(单独处理输入逻辑)
cpp 复制代码
void inputWeights(vector<double>& weights, int n) {
    cout << "请输入" << n << "个物品的重量: ";
    for (int i = 0; i < n; ++i) {
        cin >> weights[i];
    }
}

关键优化点

输入逻辑与main函数分离:使main函数更简洁,代码可读性提升,后续维护时可单独修改输入逻辑。

(4)main函数
cpp 复制代码
int main() {
    int n; // 物品数量
    double capacity; // 船舶最大载重量
    cout << "请输入物品数量和船的最大载重量: ";
    cin >> n >> capacity;

    vector<double> weights(n); // 动态数组存储物品重量
    inputWeights(weights, n); // 调用输入函数
    sort(weights.begin(), weights.end()); // 升序排序(核心步骤)

    // 输出结果
    cout << "最多能装载的物品数量: " << maxLoad(weights, capacity) << endl;

    return 0;
}

执行流程:输入参数→获取物品重量→排序→计算装载数量→输出结果,流程清晰,符合 "贪心算法步骤"。

3. 进一步可优化方向(补充建议)

  • 添加输入验证:在inputWeights和main函数中增加判断,如物品数量n需为正整数、物品重量和载重量需为非负数,避免非法输入导致程序异常,示例代码:
cpp 复制代码
// 输入物品数量时验证
while (cin >> n >> capacity, n <= 0 || capacity < 0) {
    cout << "输入无效!物品数量需为正整数,载重量需非负,请重新输入:";
}

// 输入物品重量时验证
while (cin >> weights[i], weights[i] < 0) {
    cout << "物品重量不能为负,请重新输入:";
}
  • 支持浮点数精度控制:若实际场景中对重量精度有要求(如保留 2 位小数),可使用fixed和setprecision控制输出,需添加头文件#include <iomanip>。

四、复杂度分析

1. 时间复杂度

  • 排序操作:使用 C++ 标准库 sort 函数,时间复杂度为 O(n log n)。
  • 遍历计算:maxLoad 函数中遍历 vector 数组,时间复杂度为 O(n)。
  • 整体复杂度:排序是耗时最长的操作,因此整体时间复杂度为 O(n log n),适用于中等规模数据(如 n≤10⁵),效率较高。

2. 空间复杂度

  • 主要空间消耗来自存储物品重量的vector数组,空间复杂度为O(n)。
  • 无额外复杂数据结构,空间利用率高。

五、核心知识点总结

  1. 贪心算法在船舶装载问题中的应用逻辑:"选最轻物品 → 最大化装载数量",核心是排序后依次选择;
  2. C++ 代码优化技巧:用vector替代原始数组、函数拆分(输入与计算分离)、const修饰符与引用传递;
  3. 复杂度关键:排序决定时间复杂度,数组存储决定空间复杂度;
  4. 工程化改进:输入验证、精度控制等细节可提升代码健壮性。
相关推荐
sali-tec2 小时前
C# 基于halcon的视觉工作流-章38-单位转换
开发语言·人工智能·数码相机·算法·计算机视觉·c#
念何架构之路2 小时前
Go语言数据结构和算法(七)字符串匹配算法
数据结构·算法·哈希算法
lingzhilab2 小时前
零知IDE——基于STM32F407VET6和雨滴传感器的多界面TFT降雨监测显示系统
c++·stm32·单片机
゜ eVer ㄨ2 小时前
React-router v6学生管理系统笔记
前端·笔记·react.js
试试勇气2 小时前
Linux学习笔记(七)--进程状态
笔记·学习
凯尔萨厮2 小时前
Java学习笔记五(多态)
java·笔记·学习
种自己的花呀3 小时前
leetcode 3 无重复字符的最长子串
算法·leetcode·职场和发展
轩情吖3 小时前
Qt常用控件之QTextEdit
开发语言·c++·qt·信号·qtextedit·多行输入框·桌面级开发
songyuc3 小时前
【CoaT】Co-Scale Conv-Attentional Image Transformers 译读笔记
笔记