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个上价值
元,重
千克。他希望拿走的价值尽量高,但他的背包最多只能容纳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)区间占用场地。问:安排哪些活动能够使该场地举办的活动的个数最多?
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))