贪心算法是指,在对问题求解时,总是做出在当前看来是最好的选择,不从整体最优上考虑,其实求的是在某种意义上的局部最优解。但在某些问题上贪心算法的解就是最优解
1、找零问题
假设要给你找零n元钱,钱币的面额有100元,50元,20元,5元,1元,如何找零使得所需钱币数量最少?
t = [100, 50, 20, 5, 1]
def change(t, n):
m = []
for money in t:
m.append(n // money)
n = n % money
return m, n #最后剩了n块钱
print(change(t, 281))
2、背包问题
有n个商品,第i个商品价值vi,重wi千克(输入下标的方法w~i~
,上标用x^2^
,x2)。希望选取的商品价值尽量高,但背包只能容纳W千克的东西,应该选取哪些商品?
0-1背包: 对于一个商品,要么完整的拿走,要么留下(商品为金条) (动态规划实现)
分数背包: 对于一个商品,可以拿走其中一部分(商品为金砂)
# 分数背包
goods = [(60, 10), (100, 20), (120, 30)] # 每个商品元祖表示(价格,重量)
goods.sort(key=lambda x: x[0] / x[1], reverse=True) # 对goods单位价值从大到小排序
def fractional_backpack(goods, w): # w为能装的最大重量
m = [0 for _ in range(len(goods))] # 建立一个和goods一样长的列表
total_v = 0 # 初始化总价值
for i,(price, weight) in enumerate(goods): # 枚举函数,一个一个取,i为索引值
if w >= weight:
m[i] = 1
total_v += price
w -= weight
else: # 取的下一个物品重量大于背包剩余容量
m[i] = w / weight # w为背包剩余容量,此时m[i]为一个分数
total_v += m[i] * price
w = 0 # 最后背包剩余容量为0,这句代码不写也好像能行,写上便于理解
break # 跳出循环
return total_v, m
print(fractional_backpack(goods,50))
结果对应排序后的第一个商品拿一个,第二个商品拿一个,第三个商品拿0.666666个,总价值为240.0
3、拼接最大数字问题
有n个非负整数,将其按照字符串拼接的方式拼接为一个整数,如何拼接使得到的整数最大?
from functools import cmp_to_key
li = [32, 94, 128, 1286, 6, 71]
def xy_cmp(x, y):
if x+y < y+x: # 前面是小的数加大的数,比如128和1286得1281286,比1286128小
return 1
elif x+y > y+x:
return -1
else:
return 0
def number_join(li):
li = list(map(str, li)) # 把li列表中的数字转成字符串再变成一个新列表
li.sort(key=cmp_to_key(xy_cmp)) # cmp_to_key函数返回的参数是xy_cmp函数,不会可以用冒泡排序
return ''.join(li) #join函数连接字符串
print(number_join(li))
4、活动选择问题
假设有n个活动,这些活动要占用同一片场地,而场地在某时刻只能提供一个活动使用,安排哪些活动能使该场地举办活动的个数最多?
贪心结论:最先结束的活动一定是最优解的一部分
# 一个元祖表示一个活动,数字表示开始时间和结束时间
activitives = [(1,4),(3,5),(1,6),(5,7),(3,9),(6,10),(8,11),(8,12),(2,14),(12,16)]
# 保证活动是按照结束时间排序的
activitives.sort(key=lambda x: x[1]) # sort函数会改变原有的列表
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(activitives))
学习资源
https://www.bilibili.com/video/BV1uA411N7c5?p=87