数据结构与算法:贪心算法与应用场景

news2024/10/23 12:34:21

目录

11.1 贪心算法的原理

11.2 经典贪心问题

11.3 贪心算法在图中的应用

11.4 贪心算法的优化与扩展

总结


数据结构与算法:贪心算法与应用场景

贪心算法是一种通过选择当前最佳解来构造整体最优解的算法策略。贪心算法在很多实际问题中都取得了良好的效果,尤其在那些具有贪心选择性质和最优子结构的问题上。本章将深入探讨贪心算法的基本原理、经典问题及其应用,并使用表格对比贪心算法与其他算法的不同。

11.1 贪心算法的原理

贪心算法的核心思想是每一步都采取在当前情况下最优的选择,从而希望通过一系列最优的局部选择来达到整体最优。贪心算法适用于那些能够通过局部最优解构建全局最优解的问题。

贪心算法要素描述
贪心选择性质每一步的选择都可以保证局部最优,而不影响后续决策的整体最优性。
最优子结构整体问题的最优解由各个子问题的最优解组成。
与动态规划对比贪心算法只看局部最优,而动态规划则考虑所有可能的解。

贪心算法在一些问题中非常有效,但并不是所有问题都能通过贪心策略解决。问题是否适用贪心算法,需要仔细分析其贪心选择性质和最优子结构。

11.2 经典贪心问题

贪心算法在很多经典问题中都有应用,以下是几个典型的贪心问题。

问题名称问题描述贪心策略复杂度
活动选择问题从一组活动中选择尽可能多的互不重叠的活动。每次选择最早结束的活动。O(n log n)
哈夫曼编码构建最优二进制前缀码以压缩数据。每次合并最小权值的两个节点。O(n log n)
区间调度问题安排最大数量的兼容区间活动。每次选择最早结束的区间。O(n log n)
找零问题用最少的硬币数量找零(假设硬币面值适合贪心策略)。每次选择面值最大的硬币。O(n)

代码示例:活动选择问题的实现

#include <stdio.h>
#include <stdlib.h>

struct Activity {
    int start;
    int end;
};

int compare(const void* a, const void* b) {
    return ((struct Activity*)a)->end - ((struct Activity*)b)->end;
}

void activitySelection(struct Activity activities[], int n) {
    qsort(activities, n, sizeof(struct Activity), compare);
    printf("选择的活动: \n");
    int i = 0;
    printf("(%d, %d)\n", activities[i].start, activities[i].end);
    for (int j = 1; j < n; j++) {
        if (activities[j].start >= activities[i].end) {
            printf("(%d, %d)\n", activities[j].start, activities[j].end);
            i = j;
        }
    }
}

int main() {
    struct Activity activities[] = {{1, 3}, {2, 5}, {4, 7}, {1, 8}, {5, 9}, {8, 10}};
    int n = sizeof(activities) / sizeof(activities[0]);
    activitySelection(activities, n);
    return 0;
}

在上述代码中,通过贪心策略选择最早结束的活动,可以得到一组互不重叠的活动,从而最大化所选活动的数量。

11.3 贪心算法在图中的应用

贪心算法在图论中也有广泛应用,尤其是在最小生成树和最短路径问题中。

算法名称问题描述贪心策略复杂度
Prim算法构建最小生成树,使得总权重最小。每次选择权值最小且能扩展树的边。O(V^2) 或 O(E log V)
Kruskal算法构建最小生成树,使得总权重最小。每次选择权值最小且不形成环的边。O(E log E)
Dijkstra算法从单源点出发,找到到其他各点的最短路径。每次选择当前距离最小的未处理顶点。O(V^2) 或 O(E log V)

代码示例:Prim算法的实现

#include <stdio.h>
#include <limits.h>
#include <stdbool.h>
#define V 5

int minKey(int key[], bool mstSet[]) {
    int min = INT_MAX, minIndex;
    for (int v = 0; v < V; v++) {
        if (mstSet[v] == false && key[v] < min) {
            min = key[v], minIndex = v;
        }
    }
    return minIndex;
}

void printMST(int parent[], int graph[V][V]) {
    printf("边  权重\n");
    for (int i = 1; i < V; i++) {
        printf("%d - %d    %d\n", parent[i], i, graph[i][parent[i]]);
    }
}

void primMST(int graph[V][V]) {
    int parent[V];
    int key[V];
    bool mstSet[V];
    for (int i = 0; i < V; i++) {
        key[i] = INT_MAX, mstSet[i] = false;
    }
    key[0] = 0;
    parent[0] = -1;
    for (int count = 0; count < V - 1; count++) {
        int u = minKey(key, mstSet);
        mstSet[u] = true;
        for (int v = 0; v < V; v++) {
            if (graph[u][v] && mstSet[v] == false && graph[u][v] < key[v]) {
                parent[v] = u, key[v] = graph[u][v];
            }
        }
    }
    printMST(parent, graph);
}

int main() {
    int graph[V][V] = {{0, 2, 0, 6, 0},
                       {2, 0, 3, 8, 5},
                       {0, 3, 0, 0, 7},
                       {6, 8, 0, 0, 9},
                       {0, 5, 7, 9, 0}};
    primMST(graph);
    return 0;
}

在这个代码中,通过 Prim 算法找到最小生成树,每次选择未被包含在树中的、具有最小权重的边来扩展生成树。

11.4 贪心算法的优化与扩展

虽然贪心算法在某些问题上能够很好地工作,但它的局限性在于无法保证所有情况下的全局最优解。因此,针对特定问题,可以通过以下方法对贪心算法进行优化或扩展:

优化策略描述
启发式优化在贪心选择的基础上加入启发式信息,提高对全局解的估计精度。
与动态规划结合将贪心算法与动态规划结合,使用动态规划来处理贪心策略的不足。
混合算法将贪心算法与其他算法结合,如回溯或分支限界,以求得最优解。

贪心算法在很多情况下非常高效,但对于无法满足贪心性质的问题,需要考虑其他的算法策略。通过将贪心与动态规划等方法结合,通常可以找到更优的解。

总结

本章深入介绍了贪心算法的基本原理及其在各种经典问题中的应用。通过表格比较和代码示例,我们了解了贪心算法在活动选择、最小生成树、最短路径等场景中的广泛应用。同时,我们讨论了贪心算法的局限性及其与其他算法的结合方式。在下一章中,我们将深入探讨动态规划的核心思想及其在复杂问题中的应用。

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

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

相关文章

双十一母婴必买清单 推荐超实用母婴用品

随着双十一购物狂欢节的临近&#xff0c;无数准父母和年轻家长开始摩拳擦掌&#xff0c;准备为家中的小宝贝抢购一系列高品质、实用的母婴用品。在这个年度最大的电商促销活动中&#xff0c;选择对的产品不仅能够节省开支&#xff0c;更能确保宝宝的健康成长与舒适生活。以下是…

告别微信封号!学会这5招,让你的账号坚不可摧

在这个信息爆炸的时代&#xff0c;无论是工作沟通、社交互动还是获取信息&#xff0c;微信都扮演着极其重要的角色。但是&#xff0c;随着微信平台规则的日益严格&#xff0c;账号被封的风险也随之增加。今天&#xff0c;我们就来聊聊如何有效防止 微信被封&#xff0c;让你的账…

Java基于SSM微信小程序物流仓库管理系统设计与实现(源码+lw+数据库+讲解等)

选题背景 随着社会的发展&#xff0c;社会的方方面面都在利用信息化时代的优势。互联网的优势和普及使得各种系统的开发成为必需。 本文以实际运用为开发背景&#xff0c;运用软件工程原理和开发方法&#xff0c;它主要是采用java语言技术和mysql数据库来完成对系统的设计。整个…

搞错了,再来!谷歌利用AI重新推出全新的Google Shopping

近年来&#xff0c;随着电子商务的迅猛发展&#xff0c;消费者对个性化和便捷购物体验的需求愈发高涨。谷歌&#xff0c;作为互联网巨头之一&#xff0c;一直在不断探索和创新&#xff0c;它一直在应对这样一个事实&#xff1a;越来越多的消费者首先访问零售商的网站&#xff0…

jmeter正则表达式教程

正则表达式用于提取相应数据中的代码、文本等数据&#xff0c;利用正则表达式&#xff0c;提取响应数据&#xff0c;移植到下一线程组的参数中&#xff0c;从而进行测试。 一、解释&#xff1a;解释很多&#xff0c;但是最关键 &#xff08;1&#xff09;注释不多说&#xff0c…

实验干货|电流型霍尔传感调理电路设计01

在做逆变器实验时&#xff0c;需要测量逆变器输出电压以及电流。作为初学者&#xff0c;因为缺乏经验也踩过不少坑&#xff0c;写一篇博客记录下来希望能帮到跟我一样的初学者。 踩坑回顾 用什么采样&#xff1f;片内ADC还是片外ADC&#xff1f; 早前&#xff0c;在用RTLAB做…

51单片机快速入门之 LCD1602 液晶显示屏2024/10/19

51单片机快速入门之 LCD1602 液晶显示屏 Proteus 电路图 : 74HC595 拓展电路可以不用,给 p0-p17 添加上拉电阻也可以!,我这里是方便读取和节省电阻线路 (因为之前不知道 在没有明确循环的情况下&#xff0c;Keil编译器可能会在main()中自动添加类似以下的汇编代码&#xff1a…

手机淘宝自动下单退货自动化RPA脚本机器人

使用手机集线器连接多个手机并发运行。 脚本分3个部分&#xff08;读取本地连接下单&#xff0c;退货获取退货地址信息&#xff0c;填写快递单号&#xff09; 脚本部分图结构看下面的图片 部分数据统计展示

ORACLE SELECT INTO 赋值为空,抛出 NO DATA FOUND 异常

例子&#xff1a; DECLARE ORDER_NUM VARCHAR2(20); BEGIN SELECT S.ORDER_NUM INTO ORDER_NUM FROM SALES_ORDER S WHERE S.ID122344; DBMS_OUTPUT.PUT_LINE(单号: || ORDER_NUM); END; 在查询结果为空的情况下&#xff0c;以上代码会报错&#xff1a;未找到任何数据 解决方…

1024程序员节探讨<程序员的人生观和价值观>

程序员的人生观和价值观 程序员的人生观和价值观往往受到其职业特性和工作环境的影响&#xff0c;但也会因个体差异而有所不同。 人生观 持续学习与成长&#xff1a; 程序员通常认识到技术的快速发展&#xff0c;因此他们倾向于保持一种持续学习和自我提升的态度。他们可能将…

全网最详细图文测评!Stability.AI 发布 SD3.5 Large 模型,能否逆风翻盘超越FLUX?

原文链接&#xff1a;全网最详细图文测评&#xff01;Stability.AI 发布 SD3.5 Large 模型&#xff0c;能否逆风翻盘超越FLUX&#xff1f; (chinaz.com) SD3.5 的前世今生 6 月的时候&#xff0c;Stability AI发布了 Stable Diffusion 3 Medium&#xff0c;但是在在 FLUX 发布…

FPGA学习(7)-线性序列机原理与应用,不同类型的LED控制开关

目录 1.实现1 2.实现2 2.1方法1 2.2方法2 3.实现3 3.1实验现象 4.实现4 4.1分析 4.2实现过程 4.2.1 counter的计数 4.2.2 en_counter2的判断 4.2.3 en_counter0的判断 4.2.4 对case语句加判断条件 4.3仿真结果 ​编辑 4.4实验现象 1.实现1 1.实现以下图示功能…

qt QBuffer详解

QBuffer 是 Qt 提供的一个类&#xff0c;用于在内存中操作二进制数据。它是 QIODevice 的一个子类&#xff0c;允许你将数据读入和写出到一个内存缓冲区&#xff0c;而不需要与文件系统交互。 常用方法 构造函数: QBuffer(QObject *parent nullptr): 创建一个空的 QBuffer 对象…

vue项目启动报错:exit status 1

vue项目启动报错&#xff1a;&#xff08;vite构建&#xff09; npm ERR! code ELIFECYCLE npm ERR! errno 1 npm ERR! Exit status 1 如下图所示&#xff1a; 解决 检查node版本&#xff0c;Vite 需要 Node.js 版本 18 或 20 我之前是 14.16.1&#xff0c;更换成 20.0.0 就可…

Flink 06 聚合操作入门学习,真不难

抛砖引玉 让你统计1小时内每种商品的销售额&#xff0c;用Flink 该怎么实现。 还是让你统计1小时内每种商品的销售额&#xff0c;但是要过滤掉退款的订单&#xff0c;用Flink 该怎么实现。 学了本文两个操作&#xff0c;不信你还不会。 AggregateFunction ❝ 通常用于对数据…

【决策树】- 二分法处理连续值

二分法处理连续值 在决策树算法中&#xff0c;处理连续特征通常采用二分法&#xff0c;将其转化为离散特征。此方法通过寻找最佳分割点&#xff0c;将连续特征划分为两个区间。 1. 原理 二分法的核心思想是将连续值特征转换为离散值&#xff0c;以便于决策树的构建。通过选择…

[Linux#67][IP] 报头详解 | 网络划分 | CIDR无类别 | DHCP动态分配 | NAT转发 | 路由器

目录 一. IP协议头格式 学习任何协议前的两个关键问题 IP 报头与有效载荷分离 分离方法 为什么需要16位总长度 如何交付 二. 网络通信 1.IP地址的划分理念 2. 子网管理 3.网络划分 CIDR&#xff08;无类别域间路由&#xff09; 目的IP & 当前路由器的子网掩码 …

R语言机器学习算法实战系列(九)决策树分类算法 (Decision Trees Classifier)

禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 文章目录 介绍教程下载数据加载R包导入数据数据预处理数据描述数据切割调节参数构建模型模型的决策树预测测试数据评估模型模型准确性混淆矩阵模型评估指标ROC CurvePRC Curve特征的重要性保存模…

TCP协议四次挥手

1.第一次挥手&#xff1a;客户端发送FIN报文&#xff0c;请求断开连接。这一过程为主动关闭。客户端由ESTABLISHED转换为FIN-WAIT-1。 FIN和ACK置为1&#xff0c;表示这是一个请求结束报文。seqU表示在之前客户端已经发送的字节数。ackV则表示服务端向客户端发送确认消息累计的…

磁盘分区工具 DiskGenius Pro v5.5.0.1488 中文汉化版

DiskGenius 是一款专家级数据恢复软件&#xff0c;集数据恢复、硬盘分区、系统备份还原等多种功能于一身的超级工具软件&#xff0c;功能全面&#xff0c;安全可靠。可以提供磁盘的数据找回、备份、分区、修复、删除、格式化等操作&#xff0c;也能帮助用户修复磁盘坏道、彻底删…