5.1 概念

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

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

5.2 找零问题

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

def change(t, n):  # n为n元钱
    m = [0 for _ in range(len(t))]  # 每一种零钱的张数
    for i, money in enumerate(t):  # i为下标,money为零钱种类
        m[i] = n // money
        n = n % money
    # 返回的n是没找开的钱
    return m, n 


print(change(t, 376))

5.3 背包问题

一个小偷在某个商店发现有n个商品,第i个上价值

普通背包 贪心python 贪心算法求解背包问题python_贪心算法

元,重

普通背包 贪心python 贪心算法求解背包问题python_数据结构_02

千克。他希望拿走的价值尽量高,但他的背包最多只能容纳w千克的东西。他应该拿走哪些商品?

  • 分数背包:对于一个商品,小偷可以拿走其中任意一部分。(商品为金砂)
'''
商品1:v1 = 60 w1 = 10
商品2:v2 = 100 w2 = 20
商品3:v3 = 120 w3 = 30
背包容量:W = 50
分数背包
'''
goods = [(60, 10), (100, 20), (120, 30)]  # 表示每个商品元组表示(价格, 重量)
goods.sort(key=lambda x: x[0]/x[1], reverse=True)  # 按照单位价格降序排列


def fractional_backpack(goods, w):  # goods商品 w重量
    m = [0 for _ in range(len(goods))]
    total_v = 0
    for i, (price, weight) in enumerate(goods):
        if w >= weight:
            m[i] = 1
            total_v += price
            w -= weight
        else:
            m[i] = w / weight  # 一个完整的商品都拿不走
            total_v += m[i] * price
            w = 0
            break
    return total_v, m


print(fractional_backpack(goods, 50))

5.4 拼接最大数字问题

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

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(li):
    li = list(map(str, li))  # 把数字转成字符串
    li.sort(key=cmp_to_key(xy_cmp))
    return ''.join(li)

print(number_join(li))

5.5 活动选择问题

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

普通背包 贪心python 贪心算法求解背包问题python_数据结构_03

 

普通背包 贪心python 贪心算法求解背包问题python_最优解_04

activities = [(1, 4), (3, 5), (0, 6), (5, 7), (3, 9), (5, 9), (6, 10), (8, 11), (8, 12), (2, 14), (12, 16)]
# 保证活动是按照结束时间排好序的
activities.sort(key=lambda x: x[1])

def activity_selection(a):
    res = [a[0]]
    for i in range(1, len(a)):
        if a[i][0] >= res[-1][1]:  # 当前活动的开始时间 >= 最后一个入选活动的结束时间
            # 不冲突
            res.append(a[i])  # 把活动加入
    return res


print(activity_selection(activities))