Python数据结构与算法-贪心算法(一)

news2025/1/24 14:48:16

一、贪心算法

1、定义

贪心算法(贪婪算法)是指,在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,他所作出的是在某种意义上的局部最优解。

贪心算法并不保证会得到最优解,但是在某些问题上贪心算法的解就是最优解。要会判断一个问题能否用贪心算法来计算。

2、找零问题求解

(1)问题

假设商店老板需要找零n元钱,钱币的面额有:100元、50元、20元、5元、1元,如何找零使得所需钱币的数量最少?

(2)求解思路

根据当前最优解,因此首先找到最大面值的钱币张数,可以使需要找零的张数最少,再依次递减到面值小的钱币,进行找零。例如,找零376元,先用100元找,需要3张;再用50元找,可以找1张,然后用20元找,可以找1张,之后用5元找,可以找1张,剩余的用1元找,需要1张。

(3)代码实现

t = [100,50,20,5,1] # 手上的钱,倒序排列

def change(t, n): # n是找零的钱数
    m = [0 for _ in range(len(t))] # 找零张数
    for i,money in enumerate(t):  # i是列表索引,money是索引对应的值
        m[i] = n // money   # m列表的第i个值,是找零的钱除以钱币的面值
        n = n % money # 剩余需找零的钱是取余
    return m,n # 找零张数列表,以及找不开的张数

print(change(t, 376))

输出结果:

([3, 1, 1, 1, 1], 0)

二、背包问题-贪心算法求解

1、背包问题

(1)问题背景

一个小偷在某个商店发现有n个商品,第i个商品价值vi,重wi千克。他希望拿走的价值尽量高,但他的背包最多只能容纳W千克的东西。他应该拿走哪些商品?

(2)背包问题分类

1)0-1背包:对于一个商品,小偷要么把它完整的拿走,要么留下。不能只拿走一部分,或把一个商品拿走多次。(例如:商品为金条)

2)分数背包:对于一个商品,小偷可以拿走其中任意一部分。(例如商品为金砂)

(3)背包问题分析

对于0-1背包分数背包,贪心算法是否都能得到最优解?为什么?

结论:0-1背包不可以,分数背包可以。

说明:

  • 分数背包可以拿走商品的一部分,根据贪心算法原则可以从最值钱的开始装,将整个背包的空间全部利用完。例如:装金砂和银砂,先装满金砂,有空余的位置再装银砂,直到背包装满。

  • 0-1背包不能拿走一部分商品,必须将商品全部拿走。例如:下面问题:

商品1:v1=60 ,w1=10

商品2∶v2=100 ,w2=20

商品3∶v3=120, w3=30

背包容量:W=50

按照贪心算法的原则,先拿走单价最贵的商品,商品1>商品2>商品3,因此会先装商品1,再装商品2,此时剩余空间为20,无法装下商品3,能够带走的总价值为160。然而最优解应该是带走商品2和商品3,容量刚好为50,且价值为220。

2、分数背包——贪心算法实现

(1)问题实例

分数背包问题,商品可以带走部分。

商品1:v1=60 ,w1=10

商品2∶v2=100 ,w2=20

商品3∶v3=120, w3=30

背包容量:W=50

(2)代码实现

goods = [(60,10),(120,30),(100,20)] # 每个元组代表(价值,重量),也可以用字典表示
goods.sort(key= lambda x : x[0] / x[1], reverse= True) # 根据商品单价降序排序
print(goods) 

def fractional_backpack(goods, w): # goods是列表降序排序后,w表示背包容量
    m = [0 for i in range(len(goods))] # 表示各商品可装的数量
    total_v = 0 # 总价值
    # 循环-根据贪心算法原则,求解
    for i, (price, weight) in enumerate(goods):
        if w >= weight: # 背包空间可以带走整个商品
            m[i] = 1  # 商品整个带走
            w = w - weight # 剩余背包容量
            total_v += price # 商品价值相加
        else: # w<weight, 无法将整个商品带走,只能装下一部分
            m[i] = w / weight # 可带走部分
            w = 0 # 背包容量用完
            total_v += price * m[i]  # 商品总价值 * 带走的商品数量
            break  # 跳出循环
    return total_v, m 

print(fractional_backpack(goods, 50))

结果输出:

[(60, 10), (100, 20), (120, 30)]
(240.0, [1, 1, 0.6666666666666666])

三、数字拼接问题-贪心算法

  1. 问题(p83)

(1)问题概述

有n个非负整数,将其按照字符串拼接的方式拼接为一个整数。如何拼接可以使得得到的整数最大?

例如:32,94,128,1286,6,71可以拼接除的最大整数为94716321286128。

(2)实现理论

虽然可以根据字符串的首个字符大小,再排序,使用贪心算法原则。但是存在数字大小类似的情况,例如,128,1286。通过例如,a= 128,b=1286,对比a+b和b+a的大小,确定怎么排序,得到最后的值更大。

2、代码实现

(1)知识点-函数语法

  • str()函数:参数转换成字符串类型。

a = 12
b = str(a)
print(b)

#input
"12"
  • map()函数:会根据提供的函数对指定序列做映射。第一个参数 function 以参数序列中的每一个元素调用 function 函数,返回包含每次 function 函数返回值。

语法:map(function, iterable, ...),function -- 函数,iterable -- 一个或多个序列。

# input
def add(a,b):
    return  a + b

a = [1,3,5,7]
b = [2,4,6,8]
x = map(add,a,b)
y = list(map(add,a,b))
print(x)
print(y)

# output
<map object at 0x0000020BD5404F70>
[3, 7, 11, 15]
  • join()函数:用于将序列中的元素以指定的字符连接生成一个新的字符串。

语法:str.join(sequence),sequence -- 要连接的元素序列。

# input
li = [32, 94, 128, 1286, 6, 71]
seq = list(map(str,li))
seq_join = "*".join(seq) # 用*号连接字符串
print(seq_join)

#output
32*94*128*1286*6*71
  • functools模块中的cmp_to_key部分

作用:两个传入参数x,y 当x>y时返回1 等于时返回0,否则返回-1。它在list中的工作机制就是将列表中的元素去两两比较,当cmp返回是正数时交换两元素。在list中表现为排序

# 输入
from functools import cmp_to_key # 排序模块
li = [32, 94, 128, 1286, 6, 71]

def cmp_rise(a,b):
    '''
    升序排序:
    当前面的参数a小于后面的参数b返回-1,-1代表保持不变,
    当前面的的参数a大于等于后面的参数b返回1,1代表交换顺序。
    保证前面的数字小于后面的数字
    '''
    if a < b:
        return -1
    else:
        return 1
    
x_sorted_by_rise = sorted(li,key=cmp_to_key(cmp_rise))
print(x_sorted_by_rise)

def cmp_decline(a,b):
    ''' 
    降序排序:
    当前面的参数a小于后面的参数b返回1,1代表交换顺序,
    当前面的的参数a大于等于后面的参数b返回-1,-1代表保持不变。
    因此保证了前面的数子大于后面的数字,是降序排序。
    '''
    if a < b:
        return 1
    else:
        return -1
    
x_sorted_by_decline = sorted(li, key = cmp_to_key(cmp_decline))
print(x_sorted_by_decline)

# 输出
[6, 32, 71, 94, 128, 1286]
[1286, 128, 94, 71, 32, 6]

(2)代码实现

from functools import cmp_to_key # 排序模块
li = [32, 94, 128, 1286, 6, 71]

# 根据贪心算法,将数字字符串相连后更大的数字交换位置,后拼接。
# 降序排序,原理在知识点已解析
def xy_cmp(a,b):
    if a + b < b + a: # 交换位置
        return 1 
    else:
        return -1  # 不交换位置
    
def number_join(li): # 数字拼接
    li = list(map(str, li))  # 转换为字符串
    li.sort(key=cmp_to_key(xy_cmp))  # 按xy_cmp函数的排列要求排序
    return "".join(li)  # 拍好序后的列表拼接

print(number_join(li))

输出结果:

94716321286128

四、活动选择问题-贪心算法(p85-86)

1、活动选择问题

(1)问题概述

假设有n个活动,这些活动要占用同一片场地,而场地在某时刻只能供—个活动使用。

每个活动都有一个开始时间s和结束时间f(题目中时间以整数表示),表示活动在[si, fi)区间占用场地。

问:安排哪些活动能够使该场地举办的活动的个数最多?

(2)贪心原则

1)结论:最先结束的活动一定是最优解的一部分。

2)证明:

假设a是所有活动中最先结束的活动, b是最优解中最先结束的活动。

如果a=b,结论成立。

如果ab,则b的结束时间一定晚于a的结束时间,则此时用a替换掉最优解中的b, a一定不与最优解中的其他活动时间重叠,因此替换后的解也是最优解。

2、代码实现

activities = [(0, 6), (5, 7), (3, 9), (1, 4), (3, 5), (5, 9),
              (6, 10), (2,14), (12, 16), (8, 11), (8, 12)]  # 元组列表表示(si,fi)
# 根据贪心算法结论,按最早结束时间排序
activities.sort(key = lambda x: x[1]) # 这里的x是列表中每个元组,lambda求得x[1],元组中的第二个数

def activities_selection(a): # param a:活动列表
    res = [a[0]]  # 结果列表,活动列表中最先结束活动的一定也说最优解中最先结束的活动
    for i in range(1,len(a)): # a[0]已经传入结果列表
        # 保证开始时间与上一个活动结束时间不重叠
        if a[i][0] >= res[-1][1]:  # 第i个活动的开始时间:a[i][0];上一个活动(最优解中)的结束时间:res[-1][1]
            res.append(a[i])
    
    return res

print(activities_selection(activities))

输出结果:

[(1, 4), (5, 7), (8, 11), (12, 16)]

五、贪心算法总结

  1. 用于求解最优化问题,速度较快,代码相对简单。

  1. 不是所有的最优化问题都能用贪心算法求解,例如,0-1背包问题。

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

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

相关文章

debian 10 安装prometheus 2.37.6 配置rc.local自启动

debian 10 安装prometheus 2.37.6 配置rc.local自启动 1、下载安装包2、安装3、访问普罗米修斯4、加入开机自启动4.1、配置rc-local.service4.2、添加自定义启动命令4.3、查看rc-local.service 1、下载安装包 https://prometheus.io/download/ wget -c https://github.com/pro…

人工智能前沿——「小海带」超全视觉注意力机制资源分享(附下载链接)

&#x1f4da;&#x1f4da; 人工智能 | 计算机视觉 —— 致力于目标检测领域科研Tricks改进与推荐 | 主要包括主干网络改进、轻量化网络、注意力机制、检测头部改进、空间金字塔池化、损失函数及NMS改进、ICCV/CVPR/ECCV视觉顶会创新点改进、各类数据集资源分享以及算法训练相…

Serge让你在本地运行LLaMa模型

什么是 Serge &#xff1f; Serge 是基于 llama.cpp 运行 Alpaca 模型的聊天界面。完全自托管&#xff0c;不需要 API 密钥。适合 4GB RAM 并且能在 CPU 上运行。 什么是 LLaMA ? LLaMA 是一种机器学习算法&#xff0c;全称为 Laplacian Regularized Least Squares for Multip…

windows安装mysql详解

目录 1. mysql下载2. 添加环境变量3. 添加配置文件4. 初始化 data 目录5. 安装启动服务6. 修改密码 1. mysql下载 mysql官网&#xff1a;https://www.mysql.com/downloads/ MySQL Community Server&#xff1a;MySQL数据库的服务端&#xff0c;MySQL的核心&#xff0c;只下载它…

FISCO BCOS(三十四)———商品溯源(智能合约+后端)

FISCO BCOS(三十四)———商品溯源(智能合约+后端) 一、智能合约函数调用流程 注:智能合约来源(官网的合约仓库中) 但是TraceabilityFactory合约有问题,我已经做了修改,可以看原版与我的,只有一个函数不同。 官网上这套合约在TraceabilityFactory这个合约上缺少getGo…

Springboot信息泄露以及heapdump的利用

本文转载于https://blog.csdn.net/weixin_44309905/article/details/127279561 heapdump的利用 0x01 Springboot信息泄露 路由列表 0x02 下载heapdump0x03 利用heapdump的姿势 工具一&#xff1a;heapdump_tool工具二&#xff1a;Eclipse MemoryAnalyzer 0x01 Springboot信息…

【C++11】关于C++11新特性简介

目录 一、关于C11的简介 二、统一的列表初始化 2.1 {}初始化 2.2 std::initializer_list 三、声明 3.1 auto 3.2 decltype 3.3 nullptr 四、范围for循环 五、C11中STL的一些变化 一、关于C11的简介 在2003年 C标准委员会曾经提交了一份技术勘误表(简称TC1)&#xff…

“分割一切”大模型SAM、超轻量PP-MobileSeg、工业质检工具、全景分割方案,PaddleSeg全新版本等你来体验!

图像分割是计算机视觉的一项基础技术&#xff0c;其目标是将图像中的像素按内容分成不同的类别。它在许多领域有重要应用&#xff0c;比如自动驾驶、工业质检、医疗图像分析、遥感图像解译等。 导读 PaddleSeg 是飞桨高性能图像分割开发套件&#xff0c;在图像分割领域做了大…

分类预测 | MATLAB实现BO-CNN-BiLSTM贝叶斯优化卷积双向长短期记忆网络多输入分类预测

分类预测 | MATLAB实现BO-CNN-BiLSTM贝叶斯优化卷积双向长短期记忆网络多输入分类预测 目录 分类预测 | MATLAB实现BO-CNN-BiLSTM贝叶斯优化卷积双向长短期记忆网络多输入分类预测效果一览基本介绍模型搭建程序设计参考资料 效果一览 基本介绍 MATLAB实现BO-CNN-BiLSTM贝叶斯优…

上海车展:深蓝汽车首次亮相,全场景电动出行实力圈粉

4月18日&#xff0c;2023上海国际车展如约而至。 作为疫情结束后的首个国际车展&#xff0c;本届上海车展自然吸睛无数&#xff0c;光是首个媒体日进场时的阵仗&#xff0c;就让无数媒体人高呼“人潮汹涌”。 而在本次参展的众多汽车品牌中&#xff0c;刚刚成立一周年的深蓝汽车…

【IEEE期刊专区】这本IEEE旗下期刊中科院升级为1区(TOP),什么来头?(附IEEE在检SCI目录)

近期国自然也提交等待审核了&#xff0c;放榜等到7、8月份了&#xff0c;祝愿各位科研人有好运&#xff01;现在的节点正是发表评职代表作的好时机&#xff0c;本期小编带来IEEE旗下高分区、高影响因子SCI期刊推荐&#xff0c;是不可多得的好刊代表&#xff0c;有意向作者切不可…

组件封装v-model .sync在父子组件中实现双向数据绑定 如何处理单向数据流 封装表单组件

使用watch监听 父组件使用.sync进行数据的绑定 传值子组件时 把值赋值到data的变量中 然后监听该数据的变化 $emit抛出 父组件demo <template><div><Son :model-value.sync"modelValue" :select-value.sync"selectValue" /></div>…

stata简单回归与检验

stata简单回归与检验 – 潘登同学的stata笔记 文章目录 stata简单回归与检验 -- 潘登同学的stata笔记 OLS回归系数的t检验异方差稳健型标准误计算拟合值和残差残差分析 相关系数矩阵相关矩阵散点图Pearson 相关系数Spearman 相关系数 t检验单变量t检验多变量t检验变量在多组之间…

史上最详细的八大排序详解!(建议收藏)

&#x1f680;write in front&#x1f680; &#x1f4dc;所属专栏&#xff1a;初阶数据结构 &#x1f6f0;️博客主页&#xff1a;睿睿的博客主页 &#x1f6f0;️代码仓库&#xff1a;&#x1f389;VS2022_C语言仓库 &#x1f3a1;您的点赞、关注、收藏、评论&#xff0c;是对…

Babel的深度解析

在开发中我们很少直接去接触babel&#xff0c;但是babel对于前端开发来说&#xff0c;目前是不可缺少的一部分&#xff1a; 开发中&#xff0c;我们想要使用ES6的语法&#xff0c;想要使用TypeScript&#xff0c;开发React项目&#xff0c;它们都是离不开Babel的&#xff1b; B…

性能测试分析-Java内存溢出定位案例(1)

Java内存溢出分析案例 Java常见内存溢出类型&#xff1a;堆内存溢出现象内存溢出分析下载安装分析软件下载 hprof 文件MAT 分析定位问题Shortest Paths To the Accumulation Point 内存溢出分析参考文档&#xff1a; Java常见内存溢出类型&#xff1a; 常见的内存溢出主要有以…

90、Neural Residual Radiance Fields for Streamably Free-Viewpoint Videos

简介 主页&#xff1a;https://aoliao12138.github.io/ReRF/ 前提知识&#xff1a;DeVRF&#xff1a;https://jia-wei-liu.github.io/DeVRF/ 先利用多台固定相机拍摄动态场景&#xff0c;在第一帧利用DVGO重建好半显示场景&#xff0c;后续则是通过预测体素x,y,z三个方向的运…

crontab -e 系统定时任务

crontab -e解释 crontab 是由 “cron” 和 “table” 两个单词组成的缩写。其中&#xff0c;“cron” 是一个在 Linux 和类 Unix 操作系统中用于定时执行任务的守护进程&#xff0c;而 “table” 则是指一个表格或者列表&#xff0c;因此 crontab 就是一个用于配置和管理定时任…

PHP 单笔转账到支付宝账户,支付宝公钥证书实现版本

支付宝某些业务只能使用公钥证书方式来验签 如&#xff1a;即使转账 红包等 笔者就要实现这样一个功能&#xff0c;【单笔转账到支付宝账户】&#xff0c;采用支付宝公钥证书签名来实现。 话不多说&#xff0c;流程先走起 第一步&#xff1a;下载支付宝秘钥生成器 由于我们使…

手把手教你 DVOL

分享本文在朋友圈的读者可获得本文数据和 Python 代码。留个言说已分享&#xff08;不用截屏&#xff09;我相信你&#xff0c;我会发给你百度盘下载链接。 本文长度为 6393 字&#xff0c;建议阅读 32 分钟 题图&#xff1a;SignalPlus Dashboard 0 引言 Deribit volatility (…