基于Python3的数据结构与算法 - 22 贪心算法

一、贪心算法

  • 贪心算法(又称贪婪算法)是指,在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,它所做出的是在某种意义上的局部最优解。
  • 贪心算法并不会保证会得到最优解,**但是在某些问题上贪心算法的解就是最优解。**要学会判断一个问题能否用贪心算法来计算。

1. 找零问题

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

复制代码
t = [100,50,20,5,1]

def change(t, n):   # n表示需要找零多少
    m = [0 for _ in range(len(t))]  # m = [0 0 0 0 0]  # 表示数量
    for i, money in enumerate(t):
        m[i] = n // money
        n = n % money
    return m, n

print(change(t, 376))

输出结果如下:

2. 背包问题

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

背包问题可以分为两种类型的问题:0-1背包 + 分数背包

  • 0-1背包:对于一个商品,小偷要么把它完整拿走,要么留下,不能之拿走一部分,或把一个商品拿走多次。
  • 分数背包:对于一个商品,小偷可以拿走其中任意一部分。(商品为金砂)

举例:

  • 商品1:v1 = 60 ,w1 = 10
  • 商品2:v2 = 100,w1 = 20
  • 商品3:v3 = 120, w3 = 30
  • 背包容量: W = 50

对于0-1背包 ,贪心算法不能得到最优解。(选择0-1背包最后可能出现包装不满的情况,可能剩下好多容量)

对于分数背包 ,贪心算法可以得到最优解。(选择最贵的直至包里不剩位置)

分数背包的代码实现:

复制代码
def fractional_backpack(goods, W):  # W表示最大负重
    # 贪心是指拿走单位重量更值钱的商品
    goods.sort(key=lambda x: x[0] / x[1], reverse=True)
    m = [0 for _ in range(len(goods))]  # m = [(), (), ()]   # m返回的指是对应的排好序之后的
    total_v = 0      # 总价值
    for i, (prize, weight) in enumerate(goods):
        if W >= weight:
            m[i] = 1
            W -= weight
            total_v += prize
        else:
            m[i] = W / weight
            total_v += m[i] * prize
            W = 0
            break
    return m, total_v


print(fractional_backpack(goods, 50))

3. 数字拼接问题

  • 有n个非负整数,将其按照字符串拼接的方式拼接为一个整数。如何拼接可以使得得到的整数最大?
  • 例如:32,94,128,1286,6,71可以拼接城的最大整数为94716321286128

方法一:可以通过Python中内置的 functools import cmp_to_key进行书写

复制代码
from functools import cmp_to_key

li = [32, 94, 128, 1286, 6, 71]


def xy_cmp(x, y):
    if x + y < y + x:
        return 1
    elif x + y > y + x:
        return -1
    else:
        return 0


def number_join_1(li):
    li = list(map(str, li))
    li.sort(key=cmp_to_key(xy_cmp))
    return "".join(li)

方法二:使用冒泡排序进行书写:

复制代码
def number_join_2(li):
    li = list(map(str, li))
    for i in range(len(li)):
        for j in range(i, len(li)):
            if li[i] + li[j] <= li[j] + li[i]:
                li[i], li[j] = li[j], li[i]
    return "".join(li)

4. 活动选择问题

  • 假设有n个活动,这些活动要占用同一片场地,而场地在某时刻只能供一个活动使用。
  • 每个活动都有一个开始时间si和结束时间fi(题目中时间以整数表示),表示活动在[si, fi)遇见占用场地。
  • 问:安排哪些活动能够使该场地举办的活动的个数最多?

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

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

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

示例代码如下所示:

复制代码
def activity_selection(a):
    res = [a[0]]     #res指最优解,首先只有最先开始的活动
    for i in range(1, len(a)):
        if a[i][0] >= res[-1][1]:   # a[i][0] 表示当前活动的开始时间  res[-1][1]表示最后一个活动的结束时间
            # 满足上述条件则不冲突
            res.append(a[i])
    return res

print(activity_selection(activities))
相关推荐
葫三生1 小时前
如何评价《论三生原理》在科技界的地位?
人工智能·算法·机器学习·数学建模·量子计算
m0_751336392 小时前
突破性进展:超短等离子体脉冲实现单电子量子干涉,为飞行量子比特奠定基础
人工智能·深度学习·量子计算·材料科学·光子器件·光子学·无线电电子
拓端研究室3 小时前
视频讲解:门槛效应模型Threshold Effect分析数字金融指数与消费结构数据
前端·算法
随缘而动,随遇而安5 小时前
第八十八篇 大数据中的递归算法:从俄罗斯套娃到分布式计算的奇妙之旅
大数据·数据结构·算法
美狐美颜sdk5 小时前
跨平台直播美颜SDK集成实录:Android/iOS如何适配贴纸功能
android·人工智能·ios·架构·音视频·美颜sdk·第三方美颜sdk
DeepSeek-大模型系统教程5 小时前
推荐 7 个本周 yyds 的 GitHub 项目。
人工智能·ai·语言模型·大模型·github·ai大模型·大模型学习
郭庆汝5 小时前
pytorch、torchvision与python版本对应关系
人工智能·pytorch·python
IT古董5 小时前
【第二章:机器学习与神经网络概述】03.类算法理论与实践-(3)决策树分类器
神经网络·算法·机器学习
小雷FansUnion7 小时前
深入理解MCP架构:智能服务编排、上下文管理与动态路由实战
人工智能·架构·大模型·mcp
资讯分享周7 小时前
扣子空间PPT生产力升级:AI智能生成与多模态创作新时代
人工智能·powerpoint