贪心算法原理和案例

news2024/12/22 19:42:01

目录

​编辑

贪心算法简介

什么时候使用贪心算法

贪心算法缺陷

贪心算法应用

贪心算法JAVA代码实现


贪心算法简介

        贪心算法(又称贪婪算法)Greedy Algorithm 是一种不断做出局部最优解的选择,最终期望得到全局最优解的算法。

        简单地说,贪心算法就是在每一步都做出当前最优的选择,以期望能够得到全局最优的解

        贪心算法是一种常用于求解优化问题的算法,在实际应用中,它常被用于求解一些经典问题,如背包问题、最短路径问题、最小生成树问题等。

        其中贪心算法最佳实践为用于压缩数据的霍夫曼编码(Huffman encoding)还有用于寻找图中最短路径的Dijkstra算法

什么时候使用贪心算法

        贪心算法的优点是简单、高效,容易理解和实现。但同时,由于贪心算法是基于局部最优决策的,无法保证全局最优解,所以有一定的局限性。在实践中,贪心算法通常适用于满足以下两个条件的优化问题:

  • 贪心选择性质:通过在每一步中选择最优选项(比如最小值或最大值),可以达到全局(整体)最优解。
  • .最优子结构性质:如果整个问题的最优解包含子问题的最优解,则该问题具有最优子结构。

如果上面两个性质都成立,则可以使用贪心算法来解决问题。

贪心算法缺陷

        由于贪心算法每次只考虑局部最优解,所以它无法保证能够得到全局最优解。在某些情况下,贪心算法会得到次优解甚至无解。比如下面的这一个例子。

        在下面的示例中通过贪心算法寻求找到和最大数值的路径。它通过在每一步选择最大的可用数字来实现这一点。然而,贪心算法无法找到最大的和,因为它只根据每一步所掌握的信息做出决策,而不考虑整体问题。

示例1:

在下面的图中,贪心算法试图找到最大的一个数字。它在算法的每一步中选择最大的数字。我们一眼就可以看出该算法不会得到正确的解决方案。

正确的解决方案是什么?为什么贪婪算法不适合这个问题?

        正确的找到最大数值的路径为( 7,3,1,99) 那为什么使用贪心算法不能正确的得到答案呢?因为贪心算法总是每一步去选取最大数字的路径然后沿着此路径一直寻找下去。使用贪心算法的路径为( 7 -> 12 ->6 ->9)

示例2:

此示例和上面的示例一样,在此不在赘述,大家自行理解即可。

贪心算法应用

        这里我们讲解一个使用 Dijkstra's algorithm(迪杰斯特拉算法)算法来寻找图中节点之间的最短路径。

        Dijkstra算法用于在图中查找节点之间的最短路径。该算法维护一组未访问的节点,并计算从给定节点到另一个节点的暂定距离(这个距离时临时的后面有更短的再更新)。

        如果算法发现了一种到达给定节点的更短路径,则将之前的路径更新至更短的路径。

        此问题具有令人满意的优化子结构,因为如果A连接到B,B连接到C,并且路径必须通过A和B才能到达目的地C,则从A到B的最短路径和从B到C的最短路径必须是从A到C的最短路径的一部分。因此,子问题的最优解最终形成了最终的最优解,这正是贪心算法的典型应用。

请大家在看下面的图,大家找出从 A到B最短的距离。

        在这里我们要分开多步进行探索,通过每一步找出最小路径,然后最终找到最优的路径,下面是找解的一个过程。

  • 起点 ① 出发,相邻的节点为 ②(7) ③(9) ⑥(14),很明显 ② ① 节点距离最短为 7
  • 起点② 出发,相邻的节点为 ② ③(10) ② ④(15) ,那么③① (7+10 = 17) ④①(7+15=22) ,而③直接到①的距离为9 所以 ③① 节点为最短距离,值为9。
  • 起点 ③(9) 出发,相邻节点 ③④(9+11=20) ③⑥(9+2=11) 故 ⑥ 节点为到①节点最短距离 值为11
  • 起点⑥(11) 出发 相邻节点 ⑥⑤(11 +9 = 20) ⑥①(11 +14 = 25),所以⑥⑤节点距离最短, 而 ⑤节点正是我们要到达的节点,所以a-b最短距离为 20

贪心算法JAVA代码实现

        下面我们使用JAVA代码来完成上面的这个 Dijkstra's algorithm 从图中找到a-b最短距离。代码中有详细的注释,通俗易懂。


/**
 * 用 Dijkstra 算法求解图中两节点间的最短距离
 */
public class ShortestDistance {

    public static void main(String[] args) {

        // 构造节点列表
        List<Node> nodes = buildNodeList();

        // 计算节点0和节点5之间的最短距离
        int distance = shortDistance(nodes.get(0), nodes.get(4), nodes.size());
        System.out.println("节点0 和 5 之间的最短距离是:" + distance);

    }

    /**
     * 构造节点列表
     * @return 节点列表
     */
    public static List<Node> buildNodeList() {
        List<Node> nodes = Arrays.asList(
                new Node("1"),
                new Node("2"),
                new Node("3"),
                new Node("4"),
                new Node("5"),
                new Node("6")
        );

        // 添加节点间距离
        nodes.get(0).addEdge(nodes.get(1), 7);//1-2
        nodes.get(0).addEdge(nodes.get(2), 9);//1-3
        nodes.get(0).addEdge(nodes.get(5), 14);//1-6

        nodes.get(1).addEdge(nodes.get(2), 10);//2-3
        nodes.get(1).addEdge(nodes.get(3), 15);//2-4

        nodes.get(2).addEdge(nodes.get(3), 11);//3-4
        nodes.get(2).addEdge(nodes.get(5), 2);//3-6

        nodes.get(3).addEdge(nodes.get(4), 6);//4-5

        nodes.get(4).addEdge(nodes.get(5), 9);//5-6

        return nodes;

    }

    /**
     * 通过 Dijkstra 算法计算两个节点间的最短距离
     * @param start 起始节点
     * @param end 目标节点
     * @param numsOfNodes 节点个数
     * @return 起点到目标节点的最短距离
     */
    public static int shortDistance(Node start, Node end, int numsOfNodes) {
        // 记录每个节点到起始节点的距离,初始化为最大值
        PriorityQueue<Node> pq = new PriorityQueue<>(numsOfNodes, Comparator.comparingInt(n -> n.distanceFromStart));

        // 将起始节点到自身的距离设为 0 并加入队列
        start.distanceFromStart = 0;
        pq.offer(start);

        // 使用 Dijkstra 算法计算最短路径
        while (!pq.isEmpty()) {
            // 取出为空的并且距离起点最近的节点
            Node currentNode = pq.poll();

            // 如果当前节点是目标节点,则返回当前节点到起点的距离
            if (currentNode == end) {
                return currentNode.distanceFromStart;
            }

            // 遍历当前节点的每个相邻节点并更新距离
            for (Map.Entry<Node, Integer> neighbor : sortAdjacentNode(currentNode.adjacentDistance).entrySet()) {
                Node adjacentNode = neighbor.getKey();
                Integer adjacentDistance = neighbor.getValue();

                // 计算经当前节点到该相邻节点的距离
                int distanceFromStart = currentNode.distanceFromStart + adjacentDistance;

                // 如果该距离比之前计算的距离更短,则更新距离
                if (distanceFromStart < adjacentNode.distanceFromStart) {
                    // 如果该节点已经加入过队列,将其删除
                    if (adjacentNode.isInQueue){
                        pq.remove(adjacentNode);
                    }
                    //更新该节点距离及是否在队列中
                    adjacentNode.distanceFromStart = distanceFromStart;
                    adjacentNode.isInQueue = true;
                    // 将该相邻节点加入到队列中
                    pq.offer(adjacentNode);
                }
            }
        }
        // 如果没有找到路径,则返回-1
        return -1;
    }

    /**
     * 将邻接节点排序并返回
     * @param adjacentNodes 邻接节点及其权值
     * @return 排序后的邻接节点及其权值
     */
    public static Map<Node, Integer> sortAdjacentNode(Map<Node, Integer> adjacentNodes) {
        return adjacentNodes.entrySet().stream()
                .sorted(Comparator.comparingInt(Map.Entry::getValue))
                .collect(Collectors.toMap(
                        Map.Entry::getKey,Map.Entry::getValue,(e1,e2)->e1,LinkedHashMap::new
                ));
    }

    static class Node {
        String name;
        Map<Node, Integer> adjacentDistance;
        Integer distanceFromStart = Integer.MAX_VALUE;

        // 标记该节点是否加入队列
        boolean isInQueue;

        public Node(String name) {
            this.name = name;
            adjacentDistance = new HashMap<>();
        }

        /**
         * 添加相邻节点的权重
         * @param node 相邻节点
         * @param distance 距离
         */
        public void addEdge(Node node, Integer distance) {
            this.adjacentDistance.put(node, distance);
            node.adjacentDistance.put(this, distance);
        }

        @Override
        public String toString() {
            return "Node{"+this.name+"}";
        }

    }
}

        到此,贪心算法介绍完毕,希望大家在阅读完此篇文章之后,对于贪心算法能够有一个更深入的认识,感谢大家的阅读。如大家对于贪心算法有任何疑惑之处,请留言给我。

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

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

相关文章

SpringCloud Ribbon初步应用(十)

Ribbon是客户端负载均衡&#xff0c;所以肯定集成再消费端&#xff0c;也就是consumer端 修改microservice-student-consumer-80 引入依赖&#xff0c;pom.xml 加入 ribbon相关依赖 <dependency> <groupId>org.springframework.cloud</groupId> &…

淦、我的服务器又被攻击了

「作者简介」&#xff1a;CSDN top100、阿里云博客专家、华为云享专家、网络安全领域优质创作者 「推荐专栏」&#xff1a;对网络安全感兴趣的小伙伴可以关注专栏《网络安全入门到精通》 最近老是有粉丝问我&#xff0c;被黑客攻击了&#xff0c;一定要拔网线吗&#xff1f;还有…

Python进阶语法之三元表达式详解

Python进阶语法之三元表达式详解 Python的三元表达式&#xff08;Ternary Expressions&#xff09;是一种简洁高效的编写条件逻辑的方式。与许多其他编程语言一样&#xff0c;Python也提供了三元表达式&#xff0c;可以在一行代码中写出一个if-else条件语句。在这篇博文中&…

Webpack+Babel手把手带你搭建开发环境(内附配置文件)

先简单介绍一下Webpack和Babel Webpack webpack工作就是打包&#xff0c;只要你安装的插件就可以打包一切&#xff0c;并且会自动解析依赖项&#xff0c;是前端的热门工具。Babel Ecmascript的代码一直在更新 但是浏览器的兼容却没有根上&#xff0c;babel就实现了利用服务端n…

【数据分享】1929-2022年全球站点的逐月平均能见度(Shp\Excel\12000个站点)

气象数据是在各项研究中都经常使用的数据&#xff0c;气象指标包括气温、风速、降水、能见度等指标&#xff0c;说到常用的能见度数据&#xff0c;最详细的能见度数据是具体到气象监测站点的能见度数据&#xff01; 有关气象指标的监测站点数据&#xff0c;之前我们分享过1929…

Jmeter分布式压力测试

目录 1、场景 2、原理 3、注意事项 4、slave配置 5、master配置 6、脚本执行 注意&#xff1a; 1、场景 在做性能测试时&#xff0c;单台机器进行压测可能达不到预期结果。主要原因是单台机器压到一定程度会出现瓶颈。也有可能单机网卡跟不上造成结果偏差较大。 例如4C…

Pytest教程__跳过用例的执行(7)

pytest跳过用例执行的用法与unittest跳过用例大致相同。 pytest跳过用例的方法如下&#xff1a; pytest.mark.skip(reason)&#xff1a;无条件用例。reason是跳过原因&#xff0c;下同。pytest.mark.skipIf(condition, reason)&#xff1a;condition为True时跳过用例。 pyte…

一文了解清楚前景无限的高性能计算工程师工作内容,原来和码农区别这么大 ...

随着我国对科研基建的重视以及超算互联网的部署工作正式开展&#xff0c;越来越多的人关注到了一块蓝海的就业宝藏——高性能计算工程师。当今一位高性能计算工程师人才可谓抢手至极&#xff0c;尽管年薪高涨&#xff0c;但是依然供不应求。这是未来30年都比较需要的工程技术人…

java基础(多线程)-wait/notify

一、wait/notify的原理 Owner线程发现条件不满足&#xff0c;调用wait方法&#xff0c;即可进入WaitSet变为WAITING状态 BLOCKED和WAITING的线程都处于阻塞状态&#xff0c;不占用CPU时间片BLOCKED线程会在Owner线程释放锁时唤醒WAITING线程会在Owner线程调用notify或notifyAll…

大话设计模式之——单例模式

单例&#xff08;Singleton&#xff09; Intent 确保一个类只有一个实例&#xff0c;并提供该实例的全局访问点。 Class Diagram 使用一个私有构造函数、一个私有静态变量以及一个公有静态函数来实现。 私有构造函数保证了不能通过构造函数来创建对象实例&#xff0c;只能…

Selenium+Unittest自动化测试框架实战详解

目录 前言 项目框架 首先管理时间 !/usr/bin/env python3 -- coding:utf-8 -- 配置文件 conf.py config.ini 读取配置文件 记录操作日志 简单理解POM模型 管理页面元素 封装Selenium基类 创建页面对象 熟悉unittest测试框架 编写测试用例 执行用例 生成测试报…

存储圈秘史,细说“配额管理”的那些事儿

江湖乱战 分布式存储圈管理者“配额管理”出手划天下 各方数据混战之际 管理员划分空间应接不暇 不可避免的产生资源划分不合理等问题 各路“配额管理”豪杰陆续上线&#xff0c;力求结束纷争一统江湖 职场人所熟知的办公软件“共享盘”冲锋在前 共享盘可支持多人实时上…

在Blender中制作一艘海船

今天瑞云小编给大家带了由作者Menno Snoek的Blender教程&#xff0c;一名自学成才的 3D 艺术家&#xff0c;现在已经使用 Blender 大约 2 年了&#xff0c;接下来跟着云渲染小编看下Express Shipping&#xff08;海船&#xff09;背后的工作流程。 介绍 嘿&#xff01;我叫 M…

高分子PEG:Maleimide-PEG5K-NOTA,NOTA-聚乙二醇马来酰亚胺,规格特点介绍

NOTA-PEG5000-Mal&#xff0c;Maleimide-PEG5K-NOTA&#xff0c;NOTA-聚乙二醇马来酰亚胺&#xff0c;MV5000产品结构式&#xff1a; 产品规格&#xff1a; 1.CAS号&#xff1a;N/A 2.包装规格&#xff1a;1g、5g、10g&#xff0c;包装灵活&#xff0c;有100mg包装也有500mg 1…

技术新动向 | 谷歌云大举扩展安全 AI 生态系统

【本文由 Cloud Ace 整理发布&#xff0c; Cloud Ace 是谷歌云全球战略合作伙伴&#xff0c;拥有 300 多名工程师&#xff0c;也是谷歌最高级别合作伙伴&#xff0c;多次获得 Google Cloud 合作伙伴奖。作为谷歌托管服务商&#xff0c;我们提供谷歌云、谷歌地图、谷歌办公套件…

Linux:IP地址和主机名

1、IP地址&#xff1a;每个联网的电脑都会有一个地址&#xff0c;用于和其他计算机进行通讯 IP地址目前有两个版本&#xff0c;IPv4和IPv6&#xff0c;目前最常用的是IPv4版本&#xff1b;IPv4版本的地址格式为a:b:c:d&#xff0c;a、b、c、d代表了0-255的数字 Linux中&#xf…

基于SSM的电影院购票系统开源啦

大家好&#xff0c;今天给大家带来一款SSM的电影院售票系统&#xff0c;非常不错的一个项目&#xff0c;学习javaweb编程必备。 下载地址在文末 1.SpringMVC Spring MVC属于SpringFrameWork的后续产品&#xff0c;已经融合在Spring Web Flow 里面。Spring 框架提供了构建 Web …

ESP32构建简单WebServer服务器

目录 WebServer 服务器ESP32 filesystem uploaderWebServer 库WIFI 链接网页与代码烧录 WebServer 服务器 此案例中&#xff0c;我们将创建一个最简单的 webserver 服务器 案例实现&#xff1a;ESP32 通过 SPIFFS 上传网页文件并保存&#xff0c;之后手机开启热点&#xff0c;E…

华为OD机试真题 JavaScript 实现【检查是否存在满足条件的数字组合】【2022Q4 100分】

一、题目描述 给定一个正整数数组&#xff0c;检查数组中是否存在满足规则的数字组合 规则&#xff1a;A B 2C 二、输入描述 第一行输出数组的元素个数。 接下来一行输出所有数组元素&#xff0c;用空格隔开。 三、输出描述 如果存在满足要求的数&#xff0c;在同一行…

Vue:全选多个选择框

可以使用 v-model 来绑定一个布尔类型的变量来实现全选多个选择框的功能。具体步骤如下&#xff1a; 在data中定义一个数组&#xff0c;用来存储所有需要选择的项的状态。 在模板中使用 v-for 指令循环渲染每个选择框&#xff0c;并将每个选择框的状态绑定到数组中对应的项上。…