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

目录

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 贪心算法的优化与扩展

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

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

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

总结

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Struts2标签库全解密:打造高效、动态的Web界面

文章目录 Struts2的标签通用(Generic)标签<s:property> 数据类标签<s:iterator>&#xff08;至关重要&#xff01;&#xff01;&#xff01;&#xff01;&#xff09;<s:if> <s:elseif> <s:else><s:a>超链接标签用户界面(UI)标签表单标签 …

【C++打怪之路Lv12】-- 模板进阶

#1024程序员节&#xff5c;征文# &#x1f308; 个人主页&#xff1a;白子寰 &#x1f525; 分类专栏&#xff1a;重生之我在学Linux&#xff0c;C打怪之路&#xff0c;python从入门到精通&#xff0c;数据结构&#xff0c;C语言&#xff0c;C语言题集&#x1f448; 希望得到您…

Java集合剖析4】LinkedList

目录 一、LinkedList的特有方法 二、LinkedList的底层数据结构 三、插入方法的具体实现 一、LinkedList的特有方法 LinkedList的底层是双向链表&#xff0c;它提供了操作首尾结点的方法。 二、LinkedList的底层数据结构 LinkedList的底层数据结构是一个双向链表&#xff0c;体现…

LeetCode 0908.最小差值 I:思维(遍历)

【LetMeFly】908.最小差值 I&#xff1a;思维&#xff08;遍历&#xff09; 力扣题目链接&#xff1a;https://leetcode.cn/problems/smallest-range-i/ 给你一个整数数组 nums&#xff0c;和一个整数 k 。 在一个操作中&#xff0c;您可以选择 0 < i < nums.length 的…

STM32:GPIO

目录 一、简介 二、结构 三、功能 1.GPIO 2.外部中断 四、示例 一、简介 输入输出&#xff08;IO&#xff09;是单片机最基本的外设功能之一。根据型号不同&#xff0c;STM32的IO端口数量不同&#xff0c;如64引脚的STM32F103RBT6有A、B、C、D四个IO端口&#xff0c;每个端…

追寻数组的轨迹,解开算法的情愫

公主请阅 1. 移除元素1.1 题目说明示例 1示例 2 1.2 题目分析1.3 代码部分1.4 代码分析 2. 删除有序数组中的重复项2.1 题目说明示例 1示例 3 2.2 题目分析2.3 代码部分2.4 代码分析 1. 移除元素 题目传送门 1.1 题目说明 题目描述&#xff1a; 给你一个数组 nums 和一个值 v…

代码随想录算法训练营第46期Day42

leetcode.518.零钱兑换 class Solution { public: //求装满背包有几种方法&#xff0c;公式都是&#xff1a;dp[j] dp[j - nums[i]]; // 如果求组合数就是外层for循环遍历物品&#xff0c;内层for遍历背包。 // 如果求排列数就是外层for遍历背包&#xff0c;内层for循环遍历物…

数据结构修炼——常见的排序算法:插入/希尔/选择/堆排/冒泡/快排/归并/计数

目录 一、常见的排序算法二、常见排序算法的实现2.1 排序算法回顾2.1.1 冒泡排序2.1.2 堆排序 2.2 直接插入排序2.3 希尔排序2.4 选择排序2.5 快速排序2.5.1 快速排序&#xff08;霍尔法&#xff09;2.5.2 快速排序&#xff08;挖坑法&#xff09;2.5.3 快速排序&#xff08;前…

Java实现html填充导出pdf

Java实现html填充导出pdf 1.依赖添加和pom修改 <!-- Thymeleaf 模板引擎 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency><!-- OpenPDF 库 -…

Vue3基于Element-plus的Select组建进行二次封装-demo

效果 组件 <template><ElSelectclass"follow-records-pairs-select"v-model"selectVal":placeholder"placeholder"change"selectChange"><ElOptionv-for"item in options":key"item.value":labe…

点跟踪论文—RAFT: Recurrent All-Pairs Field Transforms for Optical Flow-递归的全对场光流变换

点目标跟踪论文—RAFT: Recurrent All-Pairs Field Transforms for Optical Flow-递归的全对场光流变换 读论文RAFT密集光流跟踪的笔记 RAFT是一种新的光流深度网络结构&#xff0c;由于需要基于点去做目标的跟踪&#xff0c;因此也是阅读了像素级别跟踪的一篇ECCV 2020的经典…

Golang 怎么高效处理ACM模式输入输出

文章目录 问题bufio.NewReader高效的原理 再次提交 问题 最近在练习牛客上单调栈题目时&#xff0c;要求自己处理出入输出&#xff0c;也就是读题库要求的输入&#xff0c;计算最终结果&#xff0c;并打印输出 当我用fmt.Scan处理输入&#xff0c;用fmt.Println处理输出时&am…

使用React和Redux构建可扩展的前端应用

&#x1f496; 博客主页&#xff1a;瑕疵的CSDN主页 &#x1f4bb; Gitee主页&#xff1a;瑕疵的gitee主页 &#x1f680; 文章专栏&#xff1a;《热点资讯》 使用React和Redux构建可扩展的前端应用 1 引言 2 React入门 2.1 安装React 2.2 创建组件 3 Redux基础 3.1 安装Redu…

Jsoup在Java中:解析京东网站数据

对于电商网站如京东来说&#xff0c;其页面上的数据包含了丰富的商业洞察。对于开发者而言&#xff0c;能够从这些网站中提取有价值的信息&#xff0c;进行分析和应用&#xff0c;无疑是一项重要的技能。本文将介绍如何使用Java中的Jsoup库来解析京东网站的数据。 Jsoup简介 …

特殊类设计与设计模式

&#x1f30e;特殊类设计与设计模式 文章目录&#xff1a; 特殊类设计与设计模式 特殊类设计       设计一个只能在堆上创建对象的类       设计一个只能在栈上创建对象的类       请设计一个不能被拷贝的类       请设计一个不能被继承的类 设计模式…

【汇编语言】第一个程序(一)—— 一个源程序从写出到执行的过程

文章目录 前言1. 第一步&#xff1a;编写汇编源程序2. 第二步&#xff1a;对源程序进行编译连接3. 第三步&#xff1a;执行可执行文件中的程序结语 前言 &#x1f4cc; 汇编语言是很多相关课程&#xff08;如数据结构、操作系统、微机原理&#xff09;的重要基础。但仅仅从课程…

【GIT】.cr、.gitattributes 、 .gitignore和.git各文件夹讲解介绍

在 Git 项目中&#xff0c;.cr、.gitattributes 和 .gitignore 文件分别用于不同的配置和管理功能。下面分别解释这些文件的作用和用途&#xff1a; 1. .gitignore 文件 作用&#xff1a; .gitignore 文件用于指定哪些文件或目录应该被 Git 忽略&#xff0c;不会被追踪或提交…

大数据-185 Elasticsearch - ELK 家族 Logstash 安装配置 Input 插件-stdin stdout

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; 目前已经更新到了&#xff1a; Hadoop&#xff08;已更完&#xff09;HDFS&#xff08;已更完&#xff09;MapReduce&#xff08;已更完&am…

「C/C++」C++ STL容器库 之 std::string 字符串类

✨博客主页何曾参静谧的博客&#x1f4cc;文章专栏「C/C」C/C程序设计&#x1f4da;全部专栏「VS」Visual Studio「C/C」C/C程序设计「UG/NX」BlockUI集合「Win」Windows程序设计「DSA」数据结构与算法「UG/NX」NX二次开发「QT」QT5程序设计「File」数据文件格式「PK」Parasoli…

vue使用jquery的ajax,页面跳转

一、引入jquery依赖 打开终端更新npm npm install -g npm 更新完后引入输入npm install jquery 加载完后 在最外层的package.json文件中加入以下代码 配置好后导入jquery 设置变量用于接收服务器传输的数据 定义ajax申请数据 服务器的Controller层传输数据 &#xff08;…