【贪心算法的定义】
贪心算法(又称贪婪算法)是指在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,它所做出的是在某种意义上的局部最优解
贪心算法并不保证会得到最优解,但在某些问题上贪心算法的解就是最优解。要会判断一个问题是否用贪心算法来计算。
【问题一:找零问题】
【题目描述】
假设商店老板需要找零n元钱,钱币的面额有:100元、50元、20元、5元、1元,如何找零使得所需要的钱币的数量最少?
【题目思路】
就是首先找最大的面额的能输出几张,剩下最小的金额,再找第二大的面额的能输出几张,依次类推
首先找整除且数量最少的最大面额,再找剩下的能被整除且数量最少的最大面额,依次类推
【代码运算】
t=[100,50,20,5,1] #没有从大到小排序,需要先排序
def change(t,n): #n表示找零的金额
m=[0 for i in range(len(t))] #用于存放t里的金额都用了几张
for i,money in enumerate(t):
m[i]=n//money #最大面额的纸张能用的最大张数
n=n%money #剩下的金额
return m,n
print(change(t,376))#([3, 1, 1, 1, 1], 0)
【问题二:背包问题——分数背包求解】
【题目描述】
一个小偷在某个商店发现有n个商品,第i个商品价值vi元,中wi千克。他希望拿走的价值尽量高,但它的背包最多只能容纳W千克的东西。他应该拿走哪些商品?
【解决方案】
1. 0-1背包:对于一个商品,小偷要么把它完整拿走,要么留下。不能只拿走一部分,或把一个商品拿走多次(贪婪算法暂时先不考虑这种方法)
2.分数背包:对于一个商品,小偷可以拿走其中任意一部分。
【代码实现】
首先以单价价值更高的商品进行排序,能拿走的全拿走,到最后不能拿走的就拿走一部分,结束
li=[(60,10),(100,20),(120,30)] #商品价值和重量
li.sort(key=lambda x:x[0]/x[1],reverse=True) #根据商品的单价来排序
#print(li)
def fenshu_backpack(li,w):#w是背包的容量
m=[0 for i in range(len(li))] #用于存放装的东西
total_v=0 #获取的总价
for i,(price,weight) in enumerate(li):
if w>=weight:
m[i]=1 #1表示全拿完
total_v+=price
w-=weight
else:
m[i]=w/weight
total_v+=(m[i]*price)
w=0
break
return m,total_v
print(fenshu_backpack(li,50)) #([1, 1, 0.6666666666666666], 240.0)
【问题三:活动选择问题】
【题目描述】
假设有n个活动,这些活动要占用同一片场地,而场地在某一时刻只能供一个活动使用。
每个活动都有一个开始时间si和结束时间fi,表示活动在[si,fi)区间占用场地。
问:安排哪些活动能够使得该场地举办的活动的个数最多?
【贪心结论】
最先结束的活动一定是最优解的一部分。
证明:假设a是所有活动中最早结束的活动,b是最优解中最先结束的活动。
1.如果a=把,结论成立
2.如果a不等于b,则b的结束时间一定晚于a的结束时间,则此时用a替换掉最优解中的b,a一定不与最优解中的其他活动时间重叠,因此替换后的解还是最优解。
然后依次类推,在剩下的时间里再找最早结束的解。。。
【代码运算】
#全部活动的开始时间和结束时间
active=[(1,4),(3,5),(0,6),(5,7),(3,9),(5,9),(6,10),(8,11),(8,12),(2,14),(12,16)]
#按照活动的结束时间进行排序
def active_selected(active):
#首先将active列表中最早结束的活动保存
res=[active[0]]
#遍历后面的活动
for i in range(1,len(active)):
#如果活动的开始时间小于上一个活动结束的时间
if active[i][0]>=res[-1][1]:
res.append(active[i])
return res
print(active_selected(active)) #[(1, 4), (5, 7), (8, 11), (12, 16)]