15-C++基本算法-贪心法

news2024/11/25 18:36:40

在这里插入图片描述

📚 理论基础

贪心法(Greedy Algorithm)是一种常见的算法思想,它在每一步选择中都采取当前状态下最优的选择,以期望获得全局最优解。贪心法通常适用于问题具有最优子结构和贪心选择性质的情况。

适用场景

贪心法适用于满足以下两个条件的问题:

  1. 最优子结构:问题的最优解可以通过子问题的最优解来构建。
  2. 贪心选择性质:在每一步选择中,都采取当前状态下的最优选择。

使用步骤

贪心法的使用步骤如下:

  1. 建立数学模型:将问题转化为数学模型,明确问题的目标和约束条件。
  2. 设计贪心策略:确定每一步选择的贪心策略,即在当前状态下的最优选择。
  3. 证明贪心选择的正确性:通过数学证明或逻辑推理,证明贪心选择的正确性。
  4. 实现算法:根据贪心策略编写代码实现算法。
  5. 分析算法性能:评估算法的时间复杂度和空间复杂度,并进行性能分析。

算法缺陷

贪心法的主要缺点是局部最优不一定是全局最优。由于贪心法每一步只考虑当前状态下的最优选择,并没有考虑到全局的情况,因此在某些情况下可能得不到最优解。在应用贪心法解决问题时,需要仔细分析问题的性质,判断贪心法是否适用。

经典例子

贪心法在实际问题中有很多应用,下面介绍几个经典的例子:

  • 活动选择问题:给定一组活动,每个活动都有一个开始时间和结束时间,要求选择出最多的互不冲突的活动。
  • 钱币找零问题:给定一定面值的钞票和一个需要找零的金额,要求找出最少的钞票数量。
  • 背包问题:给定一组物品,每个物品都有一个重量和价值,背包有一定的容量限制,要求选择一些物品放入背包中,使得总价值最大。
  • 小船过河问题:有一条河,河中有一些石头,每块石头的位置和大小都不同,要求找到一种过河方案,使得每次跳石头的距离尽可能小。
  • 区间覆盖问题:给定一组区间,要求选择最少的区间,使得它们的并集覆盖了整个区间。

🎯 常见例子

活动选择问题

活动选择问题是一个经典的贪心法应用。给定一组活动,每个活动都有一个开始时间和结束时间,要求选择出最多的互不冲突的活动。

💡 思路解析:

  1. 首先,将活动按照结束时间进行排序。
  2. 初始化一个变量count,表示选择的活动数量。
  3. 选择第一个活动,并将其结束时间作为当前的最远时间。
  4. 遍历剩余的活动,如果当前活动的开始时间大于等于当前的最远时间,则选择该活动,并更新当前的最远时间。
  5. 重复上述步骤,直到遍历完所有活动。
  6. 最终,count即为选择的活动数量。

📊 表格解析:

活动编号开始时间结束时间
114
235
306
457
539
659
7610
8811
9812
10214
111216

🔀 流程图解析:

初始化
选择第一个活动
遍历剩余活动
选择该活动
是否遍历完所有活动
结束
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

struct Activity {
    int start;
    int end;
};

bool compare(Activity a, Activity b) {
    return a.end < b.end;
}

int maxActivities(vector<Activity>& activities) {
    sort(activities.begin(), activities.end(), compare);
    int count = 1;
    int end = activities[0].end;
    for (int i = 1; i < activities.size(); i++) {
        if (activities[i].start >= end) {
            count++;
            end = activities[i].end;
        }
    }
    return count;
}

int main() {
    vector<Activity> activities = {{1, 4}, {3, 5}, {0, 6}, {5, 7}, {3, 9}, {5, 9}, {6, 10}, {8, 11}, {8, 12}, {2, 14}, {12, 16}};
    int maxCount = maxActivities(activities);
    cout << "最多的互不冲突的活动数量为:" << maxCount << endl;
    return 0;
}

通过以上代码,我们可以得到最多的互不冲突的活动数量。这个例子展示了贪心法在活动选择问题中的应用,通过排序和贪心选择策略,我们选择了最多的互不冲突的活动。

钱币找零问题

钱币找零问题是另一个常见的贪心法应用。给定一定面值的钞票和一个需要找零的金额,要求找出最少的钞票数量。

💡 思路解析:

  1. 首先,将钞票按面值从大到小进行排序。
  2. 初始化一个变量count,表示所需钞票的数量。
  3. 遍历排序后的钞票列表,如果当前面值小于等于待找零金额,则将该面值的钞票加入找零结果,并更新待找零金额为剩余金额。
  4. 重复上述步骤,直到待找零金额为0或遍历完所有钞票。
  5. 最终,count即为所需钞票的数量。

📊 表格解析:

面值数量
502
200
101
50
12

🔀 流程图解析:

graph LR
A[初始化] --> B[选择第一个面值的钞票]
B --> C[待找零金额是否为0]
C --> |是| F[结束]
C --> |否| D[当前面值是否小于等于待找零金额]
D --> |是| E[加入找零结果,并更新待找零金额]
D --> |否| G[选择下一个面值的钞票]
E --> G
G --> C
#include <iostream>
#include <vector>
using namespace std;

int minCoins(vector<int>& coins, int amount) {
    int count = 0;
    for (int i = 0; i < coins.size(); i++) {
        while (amount >= coins[i]) {
            amount -= coins[i];
            count++;
        }
    }
    return count;
}

int main() {
    vector<int> coins = {1, 5, 10, 25};
    int amount = 67;
    int minCount = minCoins(coins, amount);
    cout << "最少的钞票数量为:" << minCount << endl;
    return 0;
}

通过以上代码,我们可以得到最少的钞票数量。这个例子展示了贪心法在钱币找零问题中的应用,通过贪心选择策略,我们选择了面值最大的钞票来找零,从而达到最少的钞票数量。

背包问题

背包问题是一个经典的动态规划问题,也可以使用贪心法进行求解。给定一组物品,每个物品都有一个重量和价值,背包有一定的容量限制,要求选择一些物品放入背包中,使得总价值最大。

💡 思路解析:

  1. 首先,计算每个物品的单位价值,即价值与重量的比值。
  2. 将物品按照单位价值从大到小进行排序。
  3. 初始化一个变量maxValue,表示背包中物品的总价值。
  4. 初始化一个变量capacity,表示背包的剩余容量。
  5. 遍历排序后的物品列表,如果当前物品的重量小于等于背包的剩余容量,则将该物品放入背包,并更新maxValue为当前价值,capacity为剩余容量减去当前物品的重量。
  6. 如果当前物品的重量大于背包的剩余容量,则计算当前物品的单位价值乘以背包的剩余容量,并加到maxValue上,然后结束遍历。
  7. 重复上述步骤,直到遍历完所有物品或背包的容量用尽。
  8. 最终,maxValue即为背包中物品的总价值。

📊 表格解析:

物品编号重量价值单位价值
110606
2201005
3301204

🔀 流程图解析:

graph LR
A[初始化] --> B[选择第一个物品]
B --> C{背包剩余容量是否为0}
C --> |是| F[结束]
C --> |否| D{当前物品重量是否小于等于背包剩余容量}
D --> |是| E[将物品放入背包,并更新maxValue和capacity]
D --> |否| G[计算当前物品的单位价值乘以背包剩余容量,并加到maxValue上,然后结束遍历]
E --> G
G --> C
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

struct Item {
    int weight;
    int value;
};

bool compare(Item a, Item b) {
    double ratioA = (double)a.value / a.weight;
    double ratioB = (double)b.value / b.weight;
    return ratioA > ratioB;
}

double maxValue(vector<Item>& items, int capacity) {
    sort(items.begin(), items.end(), compare);
    double maxValue = 0.0;
    for (int i = 0; i < items.size(); i++) {
        if (capacity >= items[i].weight) {
            maxValue += items[i].value;
            capacity -= items[i].weight;
        } else {
            maxValue += capacity * ((double)items[i].value / items[i].weight);
            break;
        }
    }
    return maxValue;
}

int main() {
    vector<Item> items = {{10, 60}, {20, 100}, {30, 120}};
    int capacity = 50;
    double maxVal = maxValue(items, capacity);
    cout << "背包中物品的最大总价值为:" << maxVal << endl;
    return 0;
}

通过以上代码,我们可以得到背包中物品的最大总价值。这个例子展示了贪心法在背包问题中的应用,通过排序和贪心选择策略,我们选择了单位价值最高的物品放入背包,从而达到最大的总价值。

小船过河问题

小船过河问题是一个经典的贪心法应用。假设有一条河,河中有一些石头,每块石头的位置和大小都不同,要求找到一种过河方案,使得每次跳石头的距离尽可能小。

💡 思路解析:

  1. 首先,将石头的位置进行排序。
  2. 初始化一个变量maxDistance,表示每次跳石头的最大距离。
  3. 遍历排序后的石头列表,计算相邻石头之间的距离,并更新maxDistance为最大距离。
  4. 最终,maxDistance即为每次跳石头的

最大距离。

📊 表格解析:

石头编号位置
10
22
34
47
58
69

🔀 流程图解析:

初始化
选择第一个石头
是否遍历完所有石头
结束
计算当前石头与上一个石头之间的距离
更新最大距离
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int maxDistance(vector<int>& stones) {
    sort(stones.begin(), stones.end());
    int maxDistance = 0;
    for (int i = 1; i < stones.size(); i++) {
        maxDistance = max(maxDistance, stones[i] - stones[i - 1]);
    }
    return maxDistance;
}

int main() {
    vector<int> stones = {2, 5, 7, 10, 12};
    int maxDist = maxDistance(stones);
    cout << "每次跳石头的最大距离为:" << maxDist << endl;
    return 0;
}

通过以上代码,我们可以得到每次跳石头的最大距离。这个例子展示了贪心法在小船过河问题中的应用,通过排序和贪心选择策略,我们选择了相邻石头之间的最大距离作为每次跳石头的最大距离。

区间覆盖问题

区间覆盖问题是一个经典的贪心法应用。给定一组区间,要求选择最少的区间,使得它们的并集覆盖了整个区间。

💡 思路解析:

  1. 首先,将区间按照结束时间进行排序。
  2. 初始化一个变量count,表示最少的区间数量。
  3. 初始化一个变量end,表示当前的最远结束时间。
  4. 遍历排序后的区间列表,如果当前区间的开始时间大于end,则选择该区间,并更新end为当前区间的结束时间。
  5. 重复上述步骤,直到遍历完所有区间。
  6. 最终,count即为最少的区间数量。

📊 表格解析:

区间编号开始时间结束时间
114
235
306
457
539
659
7610
8811
9812
10214
111216

🔀 流程图解析:

初始化
选择第一个区间
遍历剩余区间
选择该区间
是否遍历完所有区间
结束
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

struct Interval {
    int start;
    int end;
};

bool compare(Interval a, Interval b) {
    return a.end < b.end;
}

int minIntervals(vector<Interval>& intervals) {
    sort(intervals.begin(), intervals.end(), compare);
    int count = 1;
    int end = intervals[0].end;
    for (int i = 1; i < intervals.size(); i++) {
        if (intervals[i].start > end) {
            count++;
            end = intervals[i].end;
        }
    }
    return count;
}

int main() {
    vector<Interval> intervals = {{1, 4}, {3, 5}, {0, 6}, {5, 7}, {3, 9}, {5, 9}, {6, 10}, {8, 11}, {8, 12}, {2, 14}, {12, 16}};
    int minCount = minIntervals(intervals);
    cout << "最少的区间数量为:" << minCount << endl;
    return 0;
}

通过以上代码,我们可以得到最少的区间数量。这个例子展示了贪心法在区间覆盖问题中的应用,通过排序和贪心选择策略,我们选择了最早结束的区间,并保证每次选择的区间是不重叠的。

📝 总结

贪心法是一种常用的算法思想,适用于具有最优子结构和贪心选择性质的问题。通过选择当前状态下的最优选择,期望达到全局最优解。然而,贪心法也有局限性,局部最优不一定是全局最优。因此,在应用贪心法解决问题时,需要仔细分析问题的性质,并考虑贪心选择的正确性。

贪心法在算法设计中有很多应用,例如活动选择问题、钱币找零问题、背包问题、小船过河问题和区间覆盖问题等。这些例子展示了贪心法的思想和具体应用,希望能够帮助你理解和应用贪心法解决问题。

通过不断学习和练习,你将逐渐熟悉贪心法的思想和应用,并能够灵活运用它解决各种实际问题。加油!💪

⭐️希望本篇文章对你有所帮助。

⭐️如果你有任何问题或疑惑,请随时向提问。

⭐️感谢阅读!

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

react 实现浮动可吸附悬浮窗,悬浮球,悬浮按钮,支持拖动拖拽功能(suspend-button)

前言&#xff1a; 最近在做移动端&#xff0c;有个需求是 实现一个浮动球可拖拽&#xff0c;能吸附&#xff08;吸附到 左右两则&#xff0c;距离哪进就吸附到哪边&#xff09;。 实现过程&#xff1a; 使用 suspend-button &#xff08;但是此组件不支持 ts 和pc端&#x…

VMWare安装统信UOS虚拟机

单击 创建新的虚拟机 按钮&#xff0c;然后选择 自定义&#xff0c; 然后 下一步 硬件兼容性 选择 Workstation16.x &#xff0c;然后 下一步 选择“稍后安装操作系统”&#xff0c; 然后 下一步 选择 Linux &#xff0c; 再选 版本 CentOS 8 64位/ Ubuntu 均可&#xff0c;然…

【数据结构之树】初阶数据结构之树的实现及其各种方式(上)

文章目录 &#x1f60f;专栏导读&#x1f916;文章导读&#x1f640;树的预备知识&#x1f640;二叉树&#x1f633;树的代码实现及其各类讲解&#x1f332;树的结构体初始化 总结 &#x1f60f;专栏导读 &#x1f47b;作者简介&#xff1a;M malloc&#xff0c;致力于成为嵌入…

LinkNet分割模型搭建

原论文&#xff1a;LinkNet: Exploiting Encoder Representations for Efficient Semantic Segmentation 直接步入正题~~~ 一、LinkNet 1.decoder模块 class DecoderBlock(nn.Module):def __init__(self, in_channels, n_filters): #512, 256super(DecoderBlock, self).__in…

计算机毕业论文选题推荐|软件工程|信息管理|数据分析|系列二

文章目录 导文题目导文 计算机毕业论文选题推荐|软件工程|信息管理|数据分析|系列二 (***语言)==使用其他任何编程语言 例如:基于(***语言)门窗账务管理系统的设计与实现 得到:基于JAVA门窗账务管理系统的设计与实现 基于vue门窗账务管理系统的设计与实现 等等 题目 …

关于21电赛数字识别

这里我们只讲数字识别的代码。 关于模型的训练,这里就不多讲了,看我的这篇文章: K210学习篇(八)在MaixHub训练模型_ODF..的博客-CSDN博客 这里着重讲我们得到训练后的模型该怎么去修改以及和stm32单片机通信。 当我们把下载的模型解压后,就得到一些这些文件,我们只需…

EasyDSS视频直播点播平台如何修改登录密码与开启接口鉴权?

随着互联网的发展&#xff0c;网络安全问题也越来越受到重视。近期我们也对旗下所有的视频平台进行了技术升级&#xff0c;以增强平台的数据安全性&#xff0c;保障用户的信息安全。用户也可以通过以下指导步骤&#xff0c;对平台相关配置进行修改&#xff0c;提高保护等级。 1…

阻塞、挂起和睡眠

挂起&#xff08;主动&#xff09;和阻塞&#xff08;被动&#xff09; 本质&#xff1a;正在执行的进程/线程&#xff0c;由于某些原因主动或者被动的释放 CPU&#xff0c;暂停执行&#xff1b;挂起会将进程移出内存&#xff0c;阻塞的进程还在内存中&#xff1b;挂起时会释放…

CSDN发表文章的常用语法说明

CSDN常用语法说明 一、标题二、文本样式三、列表四、图片五、链接六、目录一级目录二级目录三级目录 七、表格八、注释九、自定义列表十、LaTeX 数学公式十一、插入甘特图十二、插入UML图十三、插入Mermaid流程图十五、插入Flowchart流程图十六、 插入类图十七、快捷键十八、脚…

汽车供应链专场对接会 | 8月25日大会同期活动

爱普搜汽车供应链对接会&#xff0c;是根据采购商的项目需求&#xff0c;有针对性地组织全国各地采购商与供应商&#xff0c;进行面对面交流与沟通&#xff0c;促成实质性交易。参会群体为汽车行业制造型企业、主机厂、Tier1/2。 供应商在参加对接会前已做足功课&#xff0c;现…

使用Linux Deploy搭建服务器(二)使用chroot容器安装linux发行版

一、先下载好软件 Linux Deploy&#xff08;一&#xff09;Linux Deploy简介与软件安装_吻等离子的博客-CSDN博客 二、搭建debian 首先手机要获取root权限 linux Deploy支持许多发行版linux&#xff0c;发行版建议选择Debian&#xff0c;这个版本最好装&#xff0c;Ubuntu …

提升互联网创业项目在搜索结果中的排名的SEO技巧

搜索引擎优化(SEO)技巧&#xff1a;提升互联网创业项目在搜索结果中的排 在当今竞争激烈的互联网创业领域&#xff0c;拥有一个高排名的搜索结果对于项目的成功至关重要。搜索引擎优化&#xff08;SEO&#xff09;是一种有效的策略&#xff0c;可以提高您的互联网创业项目在搜索…

RocketMQ 5.1.0 在java中的使用

版本&#xff1a; 当前测试版本&#xff1a;springBoot 2.3.9、 RocketMQ 5.1.0 Maven或Gradle RocketMQ的依赖项&#xff1a; <dependency><groupId>org.apache.rocketmq</groupId><artifactId>rocketmq-client</artifactId><version>5…

国内开源框架(快速开发,避免重复造轮子)

若依开源框架&#xff08;最容易上手&#xff0c;轻巧简洁&#xff09; 若依开源框架是一款基于SpringBoot2.x和Vue.js的前后端分离的权限管理系统。它采用了前后端分离的架构&#xff0c;使得系统更加灵活、易扩展。同时&#xff0c;它还集成了多种常见的功能模块&#xff0c…

UEC++: 接口

1. 2. 3. 4.一般接口的源文件是不用写逻辑的&#xff0c;一般是在接口头文件中编写 5.被C类继承&#xff1a; 写完函数&#xff0c;千万不允许定义&#xff01;&#xff01;&#xff01; 添加标记宏 找到一个类&#xff1a;继承I开头的接口&#xff1a;引用头文件 错误重写&…

移 动 端

移动端 国内的UC和QQ&#xff0c;百度等手机浏览器都是根据 Webkit 修改过来的内核 兼容移动端主流浏览器 处理 webkit 内核浏览器即可 常见移动端屏幕尺寸 调式 Chrome DevTools&#xff08;谷歌浏览器&#xff09;的模拟手机调试搭建本地 web 服务器&#xff0c; 手机和服…

嵌入式开发--STM32用DMA+IDLE中断方式串口接收不定长数据

回顾 之前讲过用 利用IDLE空闲中断来接收不定长数据 &#xff0c;但是没有用到DMA&#xff0c;其实用DMA会更加的高效&#xff0c;MCU也可以腾出更多的性能去处理应该做的事情。 原理简介 IDLE顾名思义&#xff0c;就是空闲的意思&#xff0c;即当监测到串口空闲超过1个串口…

Java---第五章(类和对象,方法带参)

Java---第五章 一 类和对象类的由来&#xff1a;二者之间的关系this关键字&#xff1a;构造方法 二 方法带参构造方法带参&#xff1a;方法带参对象数组引用数据类型作为方法参数方法重载面向对象说明面向对象和面向过程的区别 一 类和对象 类的由来&#xff1a; 人们在日常生…

【HCIA】11.ACL与NAT地址转换

ACL 通过ACL可以实现对网络中报文流的精确识别和控制&#xff0c;达到控制网络访问行为、防止网络攻击和提高网络带宽利用率的目的。 ACL是由permit或deny语句组成的一系列有顺序的规则的集合&#xff1b;它通过匹配报文的相关字段实现对报文的分类。ACL是能够匹配一个IP数据包…

结合ChatGPT制作PPT

今天看到圈友的一个AI分享&#xff0c;然后自己本身需要做一个分享的PPT。刚好那着帖子实战一下。先说下整体感受。 优点&#xff1a;制作成本确实会比较低&#xff0c;很熟练的话大概就是1分钟一个都有可能。整体流程是先找个第三方PPT制作网站&#xff0c;看下支不支持文本转…