贪心算法
贪心,顾名思义就是只考虑当前的利益,关注的是局部最优解。
1、找零问题
要找零376,贪心算法先从最大面额的100开始找,找不开再接着50,以此类推。
t = [100, 50, 20, 5, 1]
def change(t, n):
m = [0 for _ in range(len(t))]
for i, money in enumerate(t):
m[i] = n // money
n = n % money
return m, n
print(change(t, 376))
2、背包问题
单位重量的价格分别为6,5,4,商品1,2,3可以分别看作金,银,铜。贪心算法首先拿最值钱的,所以拿的商品顺序是从上到下拿。如果是0-1背包,则先拿商品1,再拿商品2,只有20容量了,放不下商品3,总共价值160。而如果不用贪心算法,拿商品2和商品3,价值220。可见这里0-1背包得不到最优解。分数背包则一定能得到最优解,因为最后背包空间一定能够装满。
分数背包代码实现:
goods = [(60,10),(100,20),(120,30)] # 每个商品元组表示(价格,重量)
goods.sort(key=lambda x: x[0]/x[1], reverse=True)
def fractional_backpack(goods, w):
m = [0 for _ in range(len(goods))]
total_v = 0
for i, (prize, weight) in enumerate(goods):
if w >= weight:
m[i] = 1
total_v += prize
w -= weight
else:
m[i] = w / weight
total_v += m[i] * prize
w = 0
break
return total_v, m
print(fractional_backpack(goods, 50))
3、数字拼接问题
拼接最大数字问题
# a = "96"
# b = "87"
# a + b if a>b else b + a
# a与b的长度可能不一样,不能直接比,相加后长度一样
# a = "128"
# b = "1286"
# a + b = "1281286"
# b + a = "1286128"
# a + b if a+b>b+a else b + a
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)) # 相当于python2的cmp功能,如果比较函数返回1则交换顺序,从而实现开头数字大的在前面
return "".join(li)
print(number_join(li))
4、活动选择问题
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))
贪心算法总结
以上四个问题共同的特点是都是最优化问题,找零问题找的是钱数量最少,背包问题找的是价值最多,拼接问题找的是整数最大,活动选择问题找的是个数最多。但并不是什么时候都能得到最优解,如背包问题里面的0-1背包就做不到。