当前位置: 首页 > news >正文

贪心算法实战:用C++搞定活动安排、最优装载和Dijkstra最短路径(附完整可运行代码)

贪心算法实战:用C++搞定活动安排、最优装载和Dijkstra最短路径(附完整可运行代码)

在算法学习的道路上,贪心算法总是让人又爱又恨——它思路简洁却暗藏玄机,代码精炼但边界条件极易出错。本文将带你用C++手撕三个经典贪心问题:活动安排、最优装载和Dijkstra最短路径。不同于教科书式的理论讲解,我们直接从工程视角出发,每个案例都提供:

  1. 可直接编译的完整代码(含标准输入输出处理)
  2. 典型测试数据集(避免自己构造数据的麻烦)
  3. 常见编译/运行时错误解决方案
  4. 关键代码段的逐行解析

1. 活动安排问题:会议室争夺战

假设你是一家创业公司的技术主管,需要为10个团队安排会议室使用时段。每个团队提交的时间段可能有重叠,如何最大化会议室利用率?这就是典型的活动安排问题。

1.1 问题建模与核心思路

贪心策略:优先选择结束时间最早的活动,为后续安排留出更多时间。这就像在自助餐厅取餐——先拿最快吃完的菜品,才能品尝更多种类。

struct Activity { int id; int start; int end; }; bool compareEndTime(const Activity &a, const Activity &b) { return a.end < b.end; // 按结束时间升序排序 }

1.2 完整实现与陷阱规避

以下代码包含三个新手常踩的坑:

#include <iostream> #include <vector> #include <algorithm> using namespace std; vector<Activity> scheduleActivities(vector<Activity>& activities) { sort(activities.begin(), activities.end(), compareEndTime); vector<Activity> selected; int lastEnd = -1; for (const auto& act : activities) { if (act.start >= lastEnd) { selected.push_back(act); lastEnd = act.end; // 特别注意:这里必须更新为当前活动的结束时间 // 常见错误:错误更新为act.start } } return selected; } int main() { vector<Activity> activities = { {1, 1, 4}, {2, 3, 5}, {3, 2, 6}, {4, 5, 7}, {5, 3, 8}, {6, 5, 9}, {7, 6, 10}, {8, 8, 11}, {9, 8, 12}, {10, 2, 13} }; auto result = scheduleActivities(activities); cout << "最多可安排活动数: " << result.size() << endl; for (const auto& act : result) { cout << "活动" << act.id << ": [" << act.start << ", " << act.end << "]" << endl; } return 0; }

注意:当存在多个活动同时满足条件时,上述代码会选择最先遇到的一个。如果需要最优解,应确保输入数据已按结束时间严格排序。

1.3 复杂度对比

操作时间复杂度空间复杂度
排序O(nlogn)O(1)
贪心选择O(n)O(n)
总复杂度O(nlogn)O(n)

2. 最优装载问题:货轮配载优化

假设你负责港口货运调度,一艘货轮载重为C,现有N个集装箱重量分别为[w1,w2,...,wn]。如何在不超过承重前提下装载最多集装箱?

2.1 算法实现与工程细节

#include <iostream> #include <vector> #include <algorithm> using namespace std; vector<int> optimalLoading(int capacity, vector<int>& weights) { sort(weights.begin(), weights.end()); vector<int> loaded; int currentLoad = 0; for (int i = 0; i < weights.size(); ++i) { if (currentLoad + weights[i] <= capacity) { loaded.push_back(weights[i]); currentLoad += weights[i]; } else { break; // 后续货物更重,无需继续检查 } } return loaded; } int main() { int capacity = 12; vector<int> weights = {8, 4, 2, 5, 7}; auto result = optimalLoading(capacity, weights); cout << "可装载集装箱数: " << result.size() << endl; cout << "具体重量: "; for (int w : result) cout << w << " "; cout << endl; return 0; }

常见调试场景

  • 当所有集装箱总重不超过capacity时,应全部装载
  • 当最轻集装箱已超重时,应返回空集
  • 存在多个相同重量集装箱时的处理

2.2 性能优化技巧

对于大规模数据(如n>1e6),可以考虑以下优化:

  1. 提前终止:当累计重量达到capacity时立即退出循环
  2. 并行排序:使用C++17的并行算法库加速排序
  3. 内存预分配:为result向量预留足够空间

3. Dijkstra最短路径:导航系统核心算法

现代地图应用的路线规划核心就是Dijkstra算法。我们实现一个带路径记忆功能的版本:

3.1 邻接表实现(适合稀疏图)

#include <iostream> #include <vector> #include <queue> #include <climits> using namespace std; vector<int> dijkstra(const vector<vector<pair<int, int>>>& graph, int start) { int n = graph.size(); vector<int> dist(n, INT_MAX); vector<int> prev(n, -1); dist[start] = 0; priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq; pq.push({0, start}); while (!pq.empty()) { auto [currentDist, u] = pq.top(); pq.pop(); if (currentDist > dist[u]) continue; for (const auto& [v, weight] : graph[u]) { if (dist[v] > dist[u] + weight) { dist[v] = dist[u] + weight; prev[v] = u; pq.push({dist[v], v}); } } } return dist; } void printPath(const vector<int>& prev, int end) { if (end == -1) return; printPath(prev, prev[end]); cout << end << " "; } int main() { // 构建图的邻接表表示 vector<vector<pair<int, int>>> graph = { {{1, 2}, {3, 1}, {5, 3}}, // 节点0 {{4, 5}, {2, 6}}, // 节点1 {{7, 6}}, // 节点2 {{1, 10}, {6, 2}}, // 节点3 {{2, 9}, {7, 4}}, // 节点4 {{3, 5}, {6, 4}}, // 节点5 {{4, 3}, {1, 7}, {7, 8}}, // 节点6 {} // 节点7 }; auto distances = dijkstra(graph, 0); cout << "从节点0出发的最短距离:" << endl; for (int i = 0; i < distances.size(); ++i) { cout << "到节点" << i << ": " << distances[i] << endl; } return 0; }

3.2 复杂度对比表

实现方式时间复杂度适用场景
邻接矩阵O(V²)稠密图
邻接表+优先队列O(E + VlogV)稀疏图
斐波那契堆O(E + VlogV)超大规模图

4. 贪心算法的适用边界

虽然贪心算法简洁高效,但并非万能。下表对比三个案例的适用条件:

问题类型能否得到最优解关键前提条件
活动安排按结束时间排序
最优装载按重量排序
单源最短路径边权非负
背包问题不能需要动态规划

在LeetCode等算法平台中,典型的贪心算法题目包括:

  • 买卖股票的最佳时机II(122题)
  • 分发饼干(455题)
  • 跳跃游戏(55题)

掌握贪心算法的核心在于培养对"局部最优能否导致全局最优"的直觉判断。这需要大量的实践积累——建议读者将本文代码手动实现一遍,修改参数观察不同输入下的输出变化。

http://www.jsqmd.com/news/989870/

相关文章:

  • ZYNQ-7010裸机环境下的触摸LCD驱动与绘图示例工程(含HDF+SDK源码)
  • 2026年知名的贵州发酵饲料/贵州富硒肉/贵州富硒饲料厂家推荐与选型指南 - 行业平台推荐
  • 数据的加密与解密(04:05)
  • STM32F103的RTC只有秒计数器?别慌,手把手教你用Unix时间戳实现完整日历(含CubeMX配置)
  • 数据的加密与解密(04:07)
  • 2026年靠谱的宿州税务规划/宿州财务外包/宿州资质办理正规公司推荐 - 品牌宣传支持者
  • 终极指南:3步打造你的专属Minecraft电影级光影世界
  • 2026年 混合机厂家最新推荐榜:不锈钢混合机/高速混合机/三维混合机/粉体混合机/干粉混合机/液体混合机源头工厂优选指南 - 品牌发掘
  • Vim 零基础核心基础篇
  • 豫北工科院校发展观察:河南机电高等专科学校及同类院校的多维比较分析 - 优质品牌商家
  • 误删照片怎么办?用PhotoRec数据恢复工具找回珍贵记忆
  • Bottles终极指南:在Linux上轻松运行Windows软件的完整解决方案
  • 从‘样品管理’到‘报告生成’:一个真实业务场景下的poi-tl附件插入实战
  • 萧山优秀的杭州喷涂设备:杭州及周边喷涂加工企业能力分析与行业指南 - 优质品牌商家
  • WebAuthn + Passkey:无密码认证新时代
  • GetQzonehistory:3步轻松备份你的QQ空间青春记忆
  • 玩转本地自动化 AI:OpenClaw 多系统部署与常见问题排查
  • 如何解决国内访问GitHub缓慢问题:Fast-GitHub完整使用指南
  • 2026年热门的拆除食品设备/二手食品设备/转让食品设备/出售食品设备长期合作厂家推荐 - 品牌宣传支持者
  • 四川排水管道非开挖修复公司电话与技术服务评测:哪家更可靠? - 优质品牌商家
  • 如何快速下载B站视频:BilibiliDown跨平台下载器完整教程
  • 华三三层交换机 企业标准完整配置
  • TMS320F28335实战工程集:SFO时钟配置+FPU浮点加速全示例
  • 2026年热门的家用电梯框架/拼装式电梯框架品牌厂家推荐 - 行业平台推荐
  • 2026泰州老地面翻新公司排行榜及选择参考 - 品牌排行榜
  • 2026年沈阳家具油漆品牌TOP榜单:环保净味、高硬度耐磨与水性漆厂家深度推荐 - 品牌发掘
  • BilibiliDown终极指南:5步掌握B站视频下载神器,打造个人媒体库
  • 学术论文写作哪个AI好?豆包、DeepSeek深度对比
  • 2026年银川工伤律师推荐指南:从工伤认定到赔偿全程维权 - 本地品牌推荐
  • 杭州艺术漆公司评价与选择指南:2026年本地市场分析 - 优质品牌商家