题目描述

问题背景

活动选择问题是贪心算法的经典应用场景之一。假设有若干个活动,每个活动都有独立的开始时间结束时间,且同一时间只能进行一个活动。要求从这些活动中选择出最大数量的不重叠活动,即任意两个选中的活动,前一个活动的结束时间不晚于后一个活动的开始时间。

输入输出示例

  • 输入(开始时间与结束时间分两行输入,空格分隔,回车结束):

    plaintext

    1 3 0 5 8 5  // 活动开始时间
    2 4 6 7 9 9  // 活动结束时间
    
  • 输出

    plaintext

    最大不重叠活动数量: 4
    
  • 解释:最优选择为活动 [1,2][3,4][5,7][8,9],共 4 个不重叠活动。

解题思路:贪心算法的核心逻辑

为什么选择贪心算法?

活动选择问题的最优解具有 “贪心选择性质”—— 每次选择最早结束的活动,能为后续活动预留最多的时间,从而最大化最终选择的活动数量。这一策略无需回溯,直接通过局部最优选择即可得到全局最优解。

算法步骤

  1. 数据组织:将每个活动的 “开始时间” 和 “结束时间” 组合成二维向量 vector<vector<int>>,每行代表一个活动(格式:[开始时间, 结束时间])。
  2. 排序:按活动的结束时间升序排序(贪心策略的关键,确保优先选择早结束的活动)。
  3. 筛选不重叠活动
    • 初始选择第一个活动(最早结束的活动),记录其结束时间。
    • 遍历后续活动,若当前活动的 “开始时间 ≥ 上一个选中活动的结束时间”,则选择该活动,并更新结束时间。
  4. 统计结果:记录最终选择的活动数量,即为答案。

完整 C++ 代码实现

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;/*** @brief 计算最大不重叠活动数量(贪心算法)* @param activities 二维向量,每行存储一个活动的[开始时间, 结束时间]*/
void selectMaxNonOverlappingActivities(vector<vector<int>>& activities) {// 边界处理:若没有活动,直接返回0if (activities.empty()) {cout << "最大不重叠活动数量: 0" << endl;return;}// 按活动结束时间升序排序(贪心算法核心:优先选早结束的活动)sort(activities.begin(), activities.end(), [](const vector<int>& activity1, const vector<int>& activity2) {return activity1[1] < activity2[1]; // 按结束时间从小到大排序});int activityCount = 1;                  // 至少选择第一个活动int lastActivityEndTime = activities[0][1]; // 记录上一个选中活动的结束时间// 遍历剩余活动,筛选不重叠的活动for (size_t i = 1; i < activities.size(); ++i) {// 若当前活动的开始时间 ≥ 上一个活动的结束时间,说明不重叠if (activities[i][0] >= lastActivityEndTime) {activityCount++; // 选择当前活动lastActivityEndTime = activities[i][1]; // 更新结束时间为当前活动的结束时间}}// 输出结果cout << "最大不重叠活动数量: " << activityCount << endl;
}int main() {vector<int> startTimes;  // 存储所有活动的开始时间vector<int> endTimes;    // 存储所有活动的结束时间vector<vector<int>> activities; // 存储所有活动([开始时间, 结束时间])int timeInput;           // 临时存储输入的时间值// 读取活动开始时间(空格分隔,回车结束)cout << "请输入所有活动的开始时间(空格分隔,回车结束):" << endl;while (cin >> timeInput) {startTimes.push_back(timeInput);// 检测到回车符,停止读取开始时间if (cin.peek() == '\n') {cin.ignore(); // 清空输入缓冲区的换行符,避免影响后续输入break;}}// 读取活动结束时间(空格分隔,回车结束)cout << "请输入所有活动的结束时间(空格分隔,回车结束):" << endl;while (cin >> timeInput) {endTimes.push_back(timeInput);if (cin.peek() == '\n') {break;}}// 输入合法性校验:开始时间和结束时间的数量必须一致if (startTimes.size() != endTimes.size()) {cerr << "输入错误:开始时间和结束时间的数量不匹配!" << endl;return 1; // 非0返回值表示程序异常退出}// 组合开始时间和结束时间,构建活动列表for (size_t i = 0; i < startTimes.size(); ++i) {activities.push_back({startTimes[i], endTimes[i]});}// 计算并输出最大不重叠活动数量selectMaxNonOverlappingActivities(activities);return 0;
}

代码细节解析

1. 边界处理与输入校验

  • 空活动判断:若输入为空(无任何活动),直接输出 0,避免数组越界。
  • 输入合法性校验:确保 “开始时间数量” 与 “结束时间数量” 一致,若不一致则提示错误并退出,避免后续逻辑异常。
  • 输入缓冲区清理:使用 cin.ignore() 清除第一个输入后的换行符,防止换行符被第二个输入循环误读。

2. 排序逻辑(Lambda 表达式)

cpp

运行

sort(activities.begin(), activities.end(), [](const vector<int>& activity1, const vector<int>& activity2) {return activity1[1] < activity2[1];});

  • 使用 Lambda 表达式作为排序的自定义比较函数,简洁高效。
  • 按活动的结束时间(activity[1])升序排序,是贪心策略的核心 —— 优先选择早结束的活动,为后续活动预留更多时间。

3. 活动筛选逻辑

  • 初始选择第一个活动(排序后最早结束的活动),activityCount 初始化为 1。
  • 遍历后续活动时,通过 activities[i][0] >= lastActivityEndTime 判断是否重叠:
    • 若满足条件:选择该活动,activityCount 加 1,并更新 lastActivityEndTime 为当前活动的结束时间。
    • 若不满足:跳过该活动,继续遍历下一个。

算法效率分析

时间复杂度空间复杂度说明
O(n log n)O(n)时间复杂度由排序操作主导(sort 函数的时间复杂度为 O (n log n));空间复杂度用于存储活动列表,为 O (n)(n 为活动数量)。

该效率是活动选择问题的最优解 —— 贪心算法无需额外的动态规划数组,在时间和空间上均优于其他解法。

测试用例验证

测试用例 1:常规输入(示例输入)

  • 开始时间:1 3 0 5 8 5
  • 结束时间:2 4 6 7 9 9
  • 排序后活动:[1,2]、[3,4]、[0,6]、[5,7]、[5,9]、[8,9]
  • 选中活动:[1,2]、[3,4]、[5,7]、[8,9]
  • 输出:4(正确)

测试用例 2:空输入

  • 开始时间:(直接回车)
  • 结束时间:(直接回车)
  • 输出:0(正确)

测试用例 3:所有活动重叠

  • 开始时间:1 2 3
  • 结束时间:4 5 6
  • 选中活动:[1,4]
  • 输出:1(正确)

测试用例 4:活动无重叠

  • 开始时间:1 3 5
  • 结束时间:2 4 6
  • 选中活动:[1,2]、[3,4]、[5,6]
  • 输出:3(正确)

总结

活动选择问题是贪心算法的典型应用,核心在于 “优先选择最早结束的活动” 这一局部最优策略。本文的实现通过清晰的数据组织、严格的输入校验和高效的排序筛选逻辑,确保了代码的正确性和可读性。

该解法不仅适用于经典的活动选择场景,还可扩展到类似问题(如会议安排、任务调度等),只需将 “活动” 替换为对应的场景实体(如会议、任务),逻辑完全复用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/97466.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/97466.shtml
英文地址,请注明出处:http://en.pswp.cn/diannao/97466.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2025年如何批量下载雪球帖子和文章导出pdf?

之前分享过雪球文章下载 2025 批量下载市场高标解读/配置喵/wangdizhe 雪球帖子/文章导出excel和pdf 这里以市场高标解读这个号为例 抓取下载的所有帖子excel数据包含文章日期&#xff0c;文章标题&#xff0c;文章链接&#xff0c;文章简介&#xff0c;点赞数&#xff0c;转…

【C++】红黑树(详解)

文章目录上文链接一、什么是红黑树二、红黑树的性质1. 颜色规则2. 红黑树的规则为什么可以控制平衡3. 红黑树的效率三、红黑树的整体结构四、红黑树的插入1. 空树的插入2. 插入节点的父亲为黑色3. 插入节点的父亲为红色(1) 叔叔为红色&#xff1a;变色(2) 叔叔为空或为黑色&…

AI提升SEO关键词效果新策略

内容概要 在2025年&#xff0c;人工智能&#xff08;AI&#xff09;技术正全面革新搜索引擎优化&#xff08;SEO&#xff09;的关键词优化模式。通过智能分析用户搜索意图与语义关联&#xff0c;AI能够精准匹配关键词并进行高效布局。本文将深入探讨AI驱动的关键词策略升级方案…

手动安装的node到nvm吧版本管理的过程。

前言 本文记录个人在使用nvm包管理器安装node 14版本 npm安装失败&#xff0c;进行手动安装的node到nvm吧版本管理的过程。 安装node 14 时 npm总是安装失败&#xff0c;如下图 通过手动下载对于版本 node下载地址 下载解压点击所需的版本下载后解压 修改解压后的文件夹名称…

Python爬虫实战:构建Widgets 小组件数据采集和分析系统

1. 引言 1.1 研究背景 在当今数字化时代,Widgets 作为用户界面的基本组成元素,广泛应用于移动应用、网站和桌面软件中,其设计质量直接影响用户体验。随着市场竞争的加剧,了解市场上各类 Widgets 产品的特征、价格区间、用户评价等信息,对于产品设计和商业决策具有重要价…

1.1 Internet简介

1.网络, 计算机网络, 互联网 2.不同的角度认识Internet1.网络, 计算机网络, 互联网 网络表示连接两点以上的通路系统比如:a.你家到邻居家的小路 -> 一个小网络b.一个村子的所有道路 -> 一个更大的网络c.送外卖的小哥骑车走的路线 -> 一个配送网络计算机网络表示专门传…

pytest使用allure测试报告

&#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 选用的项目为Selenium自动化测试Pytest框架实战&#xff0c;在这个项目的基础上说allure报告。 allure安装 首先安装python的allure-pytest包 pip install allu…

PortSwigger靶场之SQL injection with filter bypass via XML encoding通关秘籍

一、题目分析该实验室的库存查询功能存在 SQL 注入漏洞。查询结果为这些信息会出现在应用程序的响应中&#xff0c;因此您可以利用“联合”攻击来从其他表中获取数据。该数据库中有一个“用户”表&#xff0c;该表包含了已注册用户的用户名和密码。要解决&#xff0c;需进行一次…

Cocos游戏中自定义按钮组件(BtnEventComponent)的详细分析与实现

概述在Cocos游戏开发中&#xff0c;按钮交互是用户界面中最基础且重要的组成部分。原生的Cocos Button组件虽然功能完善&#xff0c;但在复杂的游戏场景中往往无法满足多样化的交互需求。本文将详细分析一个功能强大的按钮组件BtnEventComponent&#xff0c;它提供了多种交互模…

终于完成William F. Egan所著的Practical RF System Design的中文版学习资料

终于完成William F. Egan所著的Practical RF System Design的中文版学习资料 该文档聚焦RF系统的分析与设计。书中先介绍系统设计流程、书籍结构及工具&#xff08;如电子表格、测试与仿真&#xff09;&#xff0c;接着围绕RF系统关键参数展开&#xff1a;讲解增益计算&#xf…

嵌入式Linux驱动开发:蜂鸣器驱动

嵌入式Linux驱动开发&#xff1a;蜂鸣器驱动 1. 引言 本文档详细记录了基于i.MX6ULL处理器的蜂鸣器驱动开发过程。内容涵盖驱动的理论基础、代码实现、设备树配置以及用户空间应用程序的编写。本文档严格遵循用户提供的代码和文档&#xff0c;确保理论与实践的紧密结合。本文档…

Qt中的锁和条件变量和信号量

Qt中的锁和条件变量和信号量 C11中引入智能指针用来解决锁忘记释放的问题 代码如下&#xff1a; void Thread::run() {for(int i0;i<50000;i){QMutexLocker locker(&mutex);//mutex.lock();num;//mutex.unlock();} }大括号结束的时候&#xff0c;生命周期踩结束&#xf…

智能电视MaxHub恢复系统

公司的MaxHub智能电视又出故障了。 去年硬件故障返厂&#xff0c;花了8600多元。 这次看上去是软件故障。开机后蓝屏报错。 按回车键&#xff0c;电视重启。 反复折腾几次&#xff0c;自行修复执行完毕&#xff0c;终于可以进入系统了。 只不过进入windows10后&#xff0c;图…

TensorFlow 面试题及详细答案 120道(71-80)-- 性能优化与调试

《前后端面试题》专栏集合了前后端各个知识模块的面试题,包括html,javascript,css,vue,react,java,Openlayers,leaflet,cesium,mapboxGL,threejs,nodejs,mangoDB,SQL,Linux… 。 前后端面试题-专栏总目录 文章目录 一、本文面试题目录 71. 如何优化TensorFlow模…

数据结构 第三轮

以看严蔚敏老师的教材为主&#xff0c;辅以其他辅导书&#xff1a;王道&#xff0c;新编数据结构&#xff0c;学校讲义 线性结构&#xff1a;线性表、串、队列、栈、数组和广义表 树形结构、网状结构&#xff1a;图 查找、排序 动态内存管理和文件 绪论 8-29 数据&#xf…

[新启航]新启航激光频率梳 “光量子透视”:2μm 精度破除遮挡,完成 130mm 深孔 3D 建模

摘要&#xff1a;本文介绍新启航激光频率梳的 “光量子透视” 技术&#xff0c;该技术凭借独特的光量子特性与测量原理&#xff0c;以 2μm 精度破除深孔遮挡&#xff0c;成功完成 130mm 深孔的 3D 建模&#xff0c;为深孔三维形态的精确获取提供了创新解决方案&#xff0c;推动…

MongoDB /redis/mysql 界面化的数据查看页面App

MongoDB、Redis 和 MySQL 都有界面化的数据查看工具&#xff0c;以下是相关介绍&#xff1a; MongoDB 输入MongoDB的账号密码即可读取数据&#xff0c;可访问数据。 MongoDB Compass&#xff1a;这是 MongoDB 官方提供的 GUI 管理工具&#xff0c;支持 Windows、Mac 和 Linux 等…

Spring Boot 实战:接入 DeepSeek API 实现问卷文本优化

本文结合 Spring Boot 项目&#xff0c;介绍如何接入 DeepSeek API&#xff0c;自动优化问卷文本&#xff0c;并给出完整示例代码及详细注释。一、项目目标 目标是实现一个 REST 接口&#xff0c;将原始问卷文本提交给 DeepSeek API&#xff0c;然后返回优化后的文本给前端。 接…

opencv实现轮廓绘制和选择

前面学习了opencv中图像的一些处理&#xff0c;但对于opencv我们更多的还是对图像做出一些判断和识别&#xff0c;所以下面开始学习图像的识别。 原图&#xff1a; 一 图像轮廓的识别 import cv2 pencv2.imread(pen.png,0) ret,new_pencv2.threshold(pen,120,255,cv2.THRESH_…

【Linux】Docker洞察:掌握docker inspect命令与Go模板技巧

&#x1f468;‍&#x1f393;博主简介 &#x1f3c5;CSDN博客专家   &#x1f3c5;云计算领域优质创作者   &#x1f3c5;华为云开发者社区专家博主   &#x1f3c5;阿里云开发者社区专家博主 &#x1f48a;交流社区&#xff1a;运维交流社区 欢迎大家的加入&#xff01…