基于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))
相关推荐
sali-tec几秒前
C# 基于halcon的视觉工作流-章42-手动识别文本
开发语言·人工智能·算法·计算机视觉·c#·ocr
mit6.8243 分钟前
[VoiceRAG] 前端实时通信 | useRealTime钩子
人工智能
B站_计算机毕业设计之家7 分钟前
机器学习实战项目:Python+Flask 汽车销量分析可视化系统(requests爬车主之家+可视化 源码+文档)✅
人工智能·python·机器学习·数据分析·flask·汽车·可视化
CV-杨帆27 分钟前
论文阅读:arxiv 2025 Scaling Laws for Differentially Private Language Models
论文阅读·人工智能·语言模型
SandySY28 分钟前
品三国谈人性
算法·架构
羊羊小栈31 分钟前
基于「多模态大模型 + BGE向量检索增强RAG」的航空维修智能问答系统(vue+flask+AI算法)
vue.js·人工智能·python·语言模型·flask·毕业设计
viperrrrrrrrrr732 分钟前
GPT系列模型-详解
人工智能·gpt·llm
星期天要睡觉35 分钟前
模型部署——Flask 部署 PyTorch 模型
pytorch·python·flask
小欣加油37 分钟前
leetcode 62 不同路径
c++·算法·leetcode·职场和发展
夏鹏今天学习了吗37 分钟前
【LeetCode热题100(38/100)】翻转二叉树
算法·leetcode·职场和发展