贪心算法
在对问题求解时,总是作出在当前看来是最好的选择。也就是说,不从整体上加以考虑,它所作出的仅仅是在某种意义上的局部最优解(是否是全局最优,需要证明)。
最优装载问题
问题: 有一天海盗们截获了一艘装满各种各样古董的货船,每一件都价值连城,一旦打碎就是去了价值,海盗船载重量为C,每件固定的重量为wi,海盗们该如何尽可能装载最多数量的古董呢?
解决思路:
古董的种量清单:
- 船载重量固定为C,只要每次选择重量最小的古董,直到不能再装为止,这样装载的古董数量最大, 这就是贪心策略;
- 把古董按重量从小到大排序,根据策略选出尽可能多的古董。
# 定义每个古董的重量
antique = [4, 10, 7, 11, 3, 5, 14, 2]
def max_ans(antique):
# 对重量进行排序
anti_sort = sorted(antique)
# ans记录装载古董数量, tmp记录装载古董重量
ans, tmp = 0, 0
# 记录装载的古董
ship = []
for anti in anti_sort:
tmp += anti
if tmp < 30:
ans += 1
ship.append(anti)
print('装载古董的数量:', ans)
print('装载的古董:', ship)
max_ans(antique)
背包问题
问题描述:
假设山洞中有n种宝物,每种宝物有一定重量w和相应的价值v,毛驴运载能力一种宝物只能拿一样,宝物可分割。怎样才能使毛驴运走宝物的价值最大呢?
问题分析:
可以尝试三种贪心策略:
- 每次挑选价值最大的装东西入背包;
- 每次挑选最重的东西;
- 每次选取单位重量价值最大的东西。
算法设计:
- 计算出每件宝物的性价比,按照从高到低排序;
- 根据贪心策略,按性价比从大到小选取宝物,直到达到毛驴的运载能力。每次选择宝物后判断是否小于m,如果不小于则取走宝物的一部分,程序结束。
# datas中的每个元素代表一个古董,每一个列表第一个元素代表古董重量,第二个元素代表古董的价值
datas = [[4, 3], [2, 8], [9, 18], [5, 6], [5, 8], [8, 20], [5, 5], [4, 6], [5, 7], [5, 15]]
m = 30 # 毛驴运载能力
w = 0 # 获取的总价值
# 计算每件宝物的性价比,从高到底进行排序
for i in range(len(datas)):
price = datas[i][1] / datas[i][0]
# 列表中添加性价比元素
datas[i].append(price)
datas.sort(key=lambda data: data[2], reverse=True) # 从高到低
# 按照性价比从小到大进行选取宝物,直到达到毛驴的运载能力
for data in datas:
if data[0] < m:
w += data[1]
m -= data[0]
else:
w += data[2] * m
break
print('总价值:', w)
深入思考:
想一下如果宝物不可分割,贪心算法得到的是否是最优解?
注意: 物品可分割的装载问题称为背包问题,不可分割问题的装载问题称为0-1背包问题。0-1背包问题不具有贪心选择性质,贪心算法不能得到全局最优解,仅仅是最优解的近似解。0-1背包问题可用动态规划算法求解。