Python实战开发及案例分析(5)—— 贪心算法

        贪心算法是一种在每一步选择中都采取当前状态下最好或最优(即最有利)的选择,从而希望导致结果是全局最好或最优的算法。贪心算法不能保证得到最优解,但在某些问题中非常有效,并容易实现。

案例分析:找零问题

项目背景:假设你是一名收银员,需要给顾客找零,你的目标是在给出确切金额的同时,使用尽可能少的硬币。

问题设定
  • 有不同面额的硬币:1分,5分,10分,25分。
  • 需要找给顾客确切的零钱,同时使用最少的硬币。
使用 Python 实现贪心算法
def greedy_coin_change(amount, coins):
    # 初始化
    result = []
    # 从最大的硬币开始尝试
    for coin in sorted(coins, reverse=True):
        while amount >= coin:
            amount -= coin
            result.append(coin)
    return result

# 硬币面额
coins = [1, 5, 10, 25]

# 找零金额
amount = 63

# 调用函数
change = greedy_coin_change(amount, coins)

# 输出结果
print("Coins to give:", change)
print("Number of coins:", len(change))
结果分析

        这个贪心算法从最大的硬币开始,尽可能多地使用每种硬币,直到找零金额被减至零。在这种情况下,算法能够有效地减少需要使用的硬币数量。

更复杂的案例:活动选择问题

项目背景:你有一系列活动,每个活动都有一个开始时间和结束时间。你的目标是安排尽可能多的活动,使得活动之间不相互冲突。

问题设定
  • 活动由其开始和结束时间定义。
  • 选择的活动集合中任何两个活动都不能有时间上的重叠。
使用 Python 实现贪心算法
def activity_selection(activities):
    # 根据结束时间排序
    activities.sort(key=lambda x: x[1])
    # 初始化
    last_end_time = 0
    selected_activities = []

    # 选择活动
    for start, end in activities:
        if start >= last_end_time:  # 与最后选定的活动不冲突
            selected_activities.append((start, end))
            last_end_time = end

    return selected_activities

# 活动列表,每个元素是一个元组(开始时间,结束时间)
activities = [(0, 6), (3, 4), (1, 2), (5, 7), (8, 9), (5, 9)]

# 调用函数
selected = activity_selection(activities)

# 输出结果
print("Selected activities:", selected)
结果分析

        贪心策略是选择结束最早的活动,从而为后面尽可能多的活动留出时间。这种方法能够有效地最大化可以参加的活动数量。

结论

        贪心算法以其实现简单和在特定问题上的有效性而闻名。虽然它不总是能产生全局最优解,但在很多问题上,如找零问题和活动选择问题,它提供了非常高效的解决方案。在实际应用中,理解问题的结构和贪心算法的局限性是使用这种算法成功的关键。

        继续探索贪心算法的应用,我们可以考虑其他有趣的问题,比如压缩编码、图的顶点覆盖等,这些问题都可以通过贪心策略找到有效的解决方案,虽然可能不是最优解。

案例分析:霍夫曼编码

项目背景:霍夫曼编码是一种广泛使用的数据压缩方法。该算法基于字符出现频率构建最优前缀编码,频率高的字符使用较短的编码,频率低的字符使用较长的编码。

使用 Python 实现霍夫曼编码

        霍夫曼编码使用贪心策略从底部开始构建最优前缀编码树,每次合并最小的两个节点。

import heapq
from collections import Counter, namedtuple

# 定义树节点,包含字符、频率、左子节点和右子节点
class Node(namedtuple("Node", ["freq", "char", "left", "right"])):
    def __lt__(self, other):
        return self.freq < other.freq

def huffman_encoding(s):
    # 统计字符频率
    if not s:
        return None, None
    
    freq = Counter(s)
    # 使用优先队列(堆)构建森林
    forest = [Node(freq=frq, char=ch, left=None, right=None) for ch, frq in freq.items()]
    heapq.heapify(forest)
    
    # 合并森林中的树,直到只剩一个树
    while len(forest) > 1:
        left = heapq.heappop(forest)
        right = heapq.heappop(forest)
        merged = Node(left.freq + right.freq, None, left, right)
        heapq.heappush(forest, merged)
    
    # 生成编码
    def codes(node, prefix="", code={}):
        if node.char is not None:
            code[node.char] = prefix or '0'
        else:
            codes(node.left, prefix + '0', code)
            codes(node.right, prefix + '1', code)
        return code
    
    return codes(forest[0])

# 示例字符串
s = "this is an example for huffman encoding"
codes = huffman_encoding(s)

print("Character codes:")
for char, code in codes.items():
    print(f"{char}: {code}")
结果分析

        在这个案例中,通过构建一棵二叉树,并为每个字符分配一个独特的二进制码,霍夫曼编码提供了一种高效的数据压缩方法。此方法尤其适用于处理字符频率分布不均的情况。

案例分析:图的顶点覆盖

项目背景:在一个无向图中,顶点覆盖是一组顶点,使得图中的每条边至少有一个端点在此顶点集中。这是一个经典的NP完全问题。

使用 Python 实现顶点覆盖的贪心算法

        这个算法选择与最多边相连的顶点加入覆盖集,然后移除所有与这些顶点相连的边,重复此过程。

def greedy_vertex_cover(edges):
    cover = set()
    while edges:
        # 选择最多边相连的顶点
        v = max(set(sum(edges, ())), key=lambda x: sum(1 for e in edges if x in e))
        cover.add(v)
        # 移除所有与选择顶点相连的边
        edges = [e for e in edges if v not in e]
    return cover

# 示例边集
edges = [(1, 2), (2, 3), (2, 4), (3, 4), (4, 5)]
cover = greedy_vertex_cover(list(edges))
print("Vertex cover:", cover)
结果分析

        贪心算法为图的顶点覆盖问题提供了一个近似解。虽然这种方法不保证最小覆盖,但通常能快速找到一个较好的解,尤其是在大规模图中。

结论

        贪心算法在各种场景下提供了一种简单且高效的解决方案策略。在实际应用中,尽管它可能不总是产生最优解,但由于其实现简单和在特定问题上的有效性,它被广泛用于解决实际问题,从数据压缩到资源分配等领域。对于需要快速可靠解决方案的情况,贪心算法是一个非常有用的工具。

        继续探讨贪心算法的应用,我们可以进一步考虑它在路线规划、调度、网络流和其他优化问题中的使用。这些问题常见于实际工程和科学研究中,贪心策略能够提供初步解决方案,常常作为更复杂算法的基础或启发式部分。

案例分析:最短路径问题

项目背景:最短路径问题是图论中的一个经典问题,目的是找到图中两个顶点之间的最短路径。Dijkstra算法是解决这个问题的一种贪心算法。

使用 Python 实现 Dijkstra 算法

        Dijkstra算法是基于贪心策略的:在每一步选择最小的未处理的顶点,并更新其邻居的最短路径。

import heapq

def dijkstra(graph, start):
    # 初始化距离表,所有节点的距离都设置为无限大
    distances = {vertex: float('infinity') for vertex in graph}
    distances[start] = 0
    # 优先队列,保存每个顶点的最短路径和顶点名
    priority_queue = [(0, start)]

    while priority_queue:
        # 选择距离最小的顶点
        current_distance, current_vertex = heapq.heappop(priority_queue)

        # 节点的距离如果被更新过,跳过处理
        if current_distance > distances[current_vertex]:
            continue

        # 访问每个邻接的点
        for neighbor, weight in graph[current_vertex].items():
            distance = current_distance + weight

            # 只有在找到更短的路径时才进行更新
            if distance < distances[neighbor]:
                distances[neighbor] = distance
                heapq.heappush(priority_queue, (distance, neighbor))

    return distances

# 图的表示:邻接表
graph = {
    'A': {'B': 1, 'C': 4},
    'B': {'A': 1, 'C': 2, 'D': 5},
    'C': {'A': 4, 'B': 2, 'D': 1},
    'D': {'B': 5, 'C': 1}
}

start_vertex = 'A'
distances = dijkstra(graph, start_vertex)
print("Distances from start vertex:", distances)
结果分析

        Dijkstra 算法能够有效地解决最短路径问题,贪心策略在每一步选择距离最近的未处理顶点,确保了每次处理的都是当前可达的最短路径。

案例分析:任务调度问题

项目背景:在任务调度问题中,我们可能需要根据任务的紧急程度或持续时间来优先处理任务。一种常见的策略是使用最短处理时间优先(SPT)策略。

使用 Python 实现简单的任务调度
def schedule_tasks(tasks):
    # 按照任务持续时间排序
    tasks.sort(key=lambda x: x[1])  # 假设每个任务表示为(任务名, 持续时间)
    total_duration = 0
    schedule = []
    for task, duration in tasks:
        schedule.append((task, total_duration))
        total_duration += duration
    return schedule

tasks = [('Task1', 3), ('Task2', 2), ('Task3', 6), ('Task4', 1)]
scheduled = schedule_tasks(tasks)
print("Task Schedule:", scheduled)
结果分析

        按最短处理时间优先策略调度任务,可以最小化任务的平均等待时间,这种贪心策略在单个或多个资源的任务调度中非常有效。

结论

        贪心算法在许多优化问题中提供了有效的解决策略,尤其适用于那些可以通过局部最优决策逐步达到全局最优的问题。在实际应用中,虽然这些算法可能不总能保证最优解,但它们的计算效率和实现简便性使它们成为许多情况下的首选方法。对于复杂的优化问题,贪心算法常常作为更复杂算法的一部分,或者在多阶段优化过程中起到关键作用。

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

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

相关文章

记录:git上传自己的本地项目

&#x1f4da;博客主页&#xff1a;knighthood2001 ✨公众号&#xff1a;认知up吧 &#xff08;目前正在带领大家一起提升认知&#xff0c;感兴趣可以来围观一下&#xff09; &#x1f383;知识星球&#xff1a;【认知up吧|成长|副业】介绍 ❤️感谢大家点赞&#x1f44d;&…

顺序循环队列--c语言实现

#include <stdio.h> #include <stdlib.h> #include <stdbool.h>#define MAX_SIZE 100 // 假设队列的最大长度为100// 队列结构体 typedef struct {int data[MAX_SIZE]; // 存储队列元素的数组int front; // 队头指针int rear; // 队尾指针 } SeqQueue;// 初…

Python爬虫--爬取糗事百科段子

爬取糗事百科段子&#xff1a; 段子在 <div class"content"> 里面的 <span> 标签里面 不过这里有个坑&#xff0c;div 标签跟 span 标签 之间有很多空行 普通 .*? 是匹配不了的&#xff0c;需要使用模式修饰符 S S 的意思 让 .(点) 匹配&#xff0c…

C语言零基础快速入门视频教程

C语言零基础快速入门视频教程 介绍C语言C语言零基础视频教程领取教程下期更新预报 介绍C语言 C语言零基础快速入门&#xff1a;探索C语言的起源、特性与魅力 在编程世界中&#xff0c;C语言犹如一座古老而坚实的桥梁&#xff0c;连接着计算机科学的过去与现在。作为一门历史悠…

项目管理【环境】过程

系列文章目录 【引论一】项目管理的意义 【引论二】项目管理的逻辑 【环境】概述 【环境】原则 【环境】过程 一、规划和管理项目的合规性 1.1 规划和管理项目的合规性 1.2 确认合规要求 1.3 审计&#xff1a;衡量合规的程度 二、项目管理计划和项目文件 2.1 项目管理计划和…

中华科技控股集团:人工智能标准化引领者与数字化服务新航程的启航者

4月30日, 矗立于时代科技潮头的中华科技控股集团&#xff0c;自2010年在香港这片国际金融沃土上诞生以来&#xff0c;便以其独特的国资背景与全球化视野&#xff0c;肩负起推动中国科技进步与产业升级的重任。作为国资委麾下的重要一员&#xff0c;中华科技始终坚持创新驱动发展…

[C++初阶]string类

1. 为什么要学习string类 1.1 C语言中的字符串 C语言中&#xff0c;字符串是以\0结尾的一些字符的集合&#xff0c;为了操作方便&#xff0c;C标准库中提供了一些str系列的库函数&#xff0c; 但是这些库函数与字符串是分离开的&#xff0c;不太符合OOP(面向对象)的思想&…

基于HSI模型的水下图像增强算法,Matlab实现

博主简介&#xff1a; 专注、专一于Matlab图像处理学习、交流&#xff0c;matlab图像代码代做/项目合作可以联系&#xff08;QQ:3249726188&#xff09; 个人主页&#xff1a;Matlab_ImagePro-CSDN博客 原则&#xff1a;代码均由本人编写完成&#xff0c;非中介&#xff0c;提供…

MYSQL从入门到精通(二)

1、MYSQL高级概述 【1】架构概述 【2】索引优化 【3】查询截取 【4】mysql锁机制 【5】主从复制 2、MYSQL概述 【1】mysql内核 【2】sql优化工程师 【3】mysql服务器的优化 【4】各种参数常量设定 【5】查询语句优化 【6】主从复制 【7】软硬件升级 【8】容灾百分 【9】sql编…

自动安装环境shell脚本使用和运维基础使用讲解

title: 自动安装环境shell脚本使用和运维基础使用讲解 tags: [shell,linux,运维] categories: [开发记录,系统运维] date: 2024-3-27 14:10:15 description: 准备和说明 确认有网。 依赖程序集&#xff0c;官网只提供32位压缩包&#xff0c;手动编译安装后&#xff0c;在64位机…

springboot整合mybatis配置多数据源(mysql/oracle)

目录 前言导入依赖坐标创建mysql/oracle数据源配置类MySQLDataSourceConfigOracleDataSourceConfig application.yml配置文件配置mysql/oracle数据源编写Mapper接口编写Book实体类编写测试类 前言 springboot整合mybatis配置多数据源&#xff0c;可以都是mysql数据源&#xff…

QT:布局管理器

文章目录 垂直布局使用QVBoxLayout来管理多个控件 水平布局使用QHBoxLayout管理控件 网格布局创建QGridLayout管理四个按钮设置元素的大小比例 表单布局 在之前QT的界面控件中&#xff0c;都是使用绝对定位来完成的&#xff0c;也就是说是用绝对坐标的方式来设置进去的 这样并…

网站高级认证页面模板(自定义安全认证)

网站高级认证页面模板&#xff08;自定义安全认证&#xff09; 仅限于源码测试&#xff0c;不代表真实性 下载地址&#xff1a; https://yuncv.lanzouw.com/i98qC1xm8u4j

ue引擎游戏开发笔记(29)——实现第三人称角色随手柄力度进行移动

1.需求分析 角色可以随手柄力量大小进行走路和跑步&#xff0c;不动时保持角色停顿。 2.操作实现 1.思路&#xff1a;通过动画蓝图和动画混合实现角色移动和输入的联系。 2.建立动画蓝图和混合空间&#xff1a; 3.在混合空间中对角色移动进行编辑&#xff1a; 4.在蓝图中设定变…

Springboot图片上传【本地+oss】

文章目录 1 前端组件页面2 本地上传3 上传到阿里云oss3.1申请开通账号&#xff0c;做好先导准备3.2 开始使用 1 前端组件页面 使用的VueElement组件 在线cdn引入&#xff1a; <script src"https://cdn.bootcdn.net/ajax/libs/vue/2.7.16/vue.js"></script&…

深入教程:在STM32上实现能源管理系统

引言 能源管理系统&#xff08;EMS&#xff09;在提高能源效率、减少能源消耗和支持可持续发展方面起着关键作用。本教程将介绍如何在STM32微控制器上开发一个能源管理系统&#xff0c;这种系统能够监控和控制能源使用&#xff0c;适用于家庭自动化、工业控制系统以及任何需要…

ARP欺骗使局域网内设备断网

一、实验准备 kali系统&#xff1a;可使用虚拟机软件模拟 kali虚拟机镜像链接&#xff1a;https://www.kali.org/get-kali/#kali-virtual-machines 注意虚拟机网络适配器采用桥接模式 局域网内存在指定断网的设备 二、实验步骤 打开kali系统命令行&#xff1a;ctrlaltt可快…

定点小数_

目录 定点小数表示和运算 定点小数的原码 定点小时加减法运算 定点小数 vs 定点整数 定点小数表示和运算 定点小数的原码 定点小数原反补转换 定点小时加减法运算 定点小数 vs 定点整数 定点小数原码依然是 取值范围等比数列 符号位 定点小数 同样的:

QT5之事件——包含提升控件

事件概述 信号就是事件的一种&#xff0c;事件由用户触发&#xff1b; 鼠标点击窗口&#xff0c;也可以检测到事件&#xff1b;产生事件后&#xff0c;传给事件处理&#xff0c;判断事件类型&#xff0c;后执行事件相应函数&#xff1b; 类似单片机的中断&#xff08;中断向量…

C语言 联合和枚举

目录 1. 联合体1.1 联合体类型的声明1.2 联合体变量的创建1.3 联合体的特点1.4 联合体在内存中的存储1.5 联合体使用举例 2. 枚举类型2.1 枚举类型的声明2.2 枚举变量的创建和初始化2.3 枚举类型的大小2.4 枚举类型的优点 正文开始 上次我们通过《C语言 结构体详解》学习了结构…
最新文章