基于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))
相关推荐
AndrewHZ6 分钟前
【图像处理基石】如何入门大规模三维重建?
人工智能·深度学习·大模型·llm·三维重建·立体视觉·大规模三维重建
5G行业应用10 分钟前
【赠书福利,回馈公号读者】《智慧城市与智能网联汽车,融合创新发展之路》
人工智能·汽车·智慧城市
悟空胆好小19 分钟前
分音塔科技(BABEL Technology) 的公司背景、股权构成、产品类型及技术能力的全方位解读
网络·人工智能·科技·嵌入式硬件
探讨探讨AGV19 分钟前
以科技赋能未来,科聪持续支持青年创新实践 —— 第七届“科聪杯”浙江省大学生智能机器人创意竞赛圆满落幕
人工智能·科技·机器人
cwn_36 分钟前
回归(多项式回归)
人工智能·机器学习·数据挖掘·回归
??tobenewyorker44 分钟前
力扣打卡第23天 二叉搜索树中的众数
数据结构·算法·leetcode
贝塔西塔1 小时前
一文读懂动态规划:多种经典问题和思路
算法·leetcode·动态规划
聚客AI1 小时前
🔥 大模型开发进阶:基于LangChain的异步流式响应与性能优化
人工智能·langchain·agent
cooldream20091 小时前
Python 包管理新时代:深入了解 `uv` 的使用与实践
python·uv·包管理器
之歆1 小时前
Python-魔术方法-创建、初始化与销毁-hash-bool-可视化-运算符重载-容器和大小-可调用对象-上下文管理-反射-描述器-二分-学习笔记
笔记·python·学习