一:贪心算法
贪心算法(又称贪婪算法)是指:在求解问题时,总是做出在当前看来最好的选择。也就是说,不从整体最优加以考虑,它所作出的是在某种意义上的局部最优解。对于有些问题,贪心算法最终可以得到整体最优解,但是对于另外一些问题,它可能只会得到局部最优解,但是最终结果都是朝着整体最优解去的。
贪心算法是动态规划的一种特例,贪心算法的每一次选择都会对最后结果产生影响,而动态规划则不会。贪心算法在做出每一步选择之后,不能回退;动态规划则会根据以前的选择结果对当前进行选择,可以回退。所以,能用贪心算法解决的问题,也可以用动态规划解决。
二:活动安排问题
2.1: 问题描述
有n个需要在同一天使用同一个教室的活动,每个活动都有开始时间和结束时间,请安排这些活动使得尽量多的活动可以不冲突的举行
2.2:解决思路
我们最终的目标是使得有尽量多的活动可以举行。那么怎样才能保证有足够多的活动可以举行呢?如果一个活动的结束时间越早,那么留给其他活动的时间就越多。所以,我们在每一步只需要选取最先结束的活动举行即可。这样,所选择的每一个活动都是在当前最先结束的,自然最后举行的活动数量就多了。
2.3:示例代码
class Activity:
def __init__(self,startTime,endTime):
self.startTime = startTime
self.endTime = endTime
# 创建活动队列
def ActivityList():
activity = []
act1 = Activity(1,4)
act2 = Activity(3,5)
act3 = Activity(0,6)
act4 = Activity(5,7)
act5 = Activity(3,8)
act6 = Activity(5,9)
act7 = Activity(6,10)
act8 = Activity(8,11)
act9 = Activity(8,12)
act10 = Activity(2,13)
act11 = Activity(12,14)
activity.append(act1)
activity.append(act2)
activity.append(act3)
activity.append(act4)
activity.append(act5)
activity.append(act6)
activity.append(act7)
activity.append(act8)
activity.append(act9)
activity.append(act10)
activity.append(act11)
return activity
# 根据活动结束时间从小到达排序
def Sort(list):
for i in range(len(list)):
for j in range(i+1,len(list)):
if list[i].endTime > list[j].endTime:
temp = list[i]
list[i] = list[j]
list[j] = temp
return list
# 贪心算法寻找最优解决方案
def Find_Best_Activity(list,starttime,endtime):
nowTime = starttime
BestActivity = []
for i in range(len(list)):
if list[i].startTime >= nowTime and list[i].endTime <= endtime:
BestActivity.append(list[i])
nowTime = list[i].endTime
return BestActivity
def main():
activity = ActivityList()
sort_activity = Sort(activity)
best_activity = Find_Best_Activity(sort_activity,0,15)
for i in range(len(best_activity)):
print('Activity [startTime=%3d , endTime=%3d]' % (best_activity[i].startTime,best_activity[i].endTime))
if __name__ == '__main__':
main()
三:钱币找零问题
3.1:问题描述
假设有1元、2元、5元、10元、20元、50元、100元纸币分别有Num0,Num1,Num2,NUm3,Num4,Num5,Num6张。现在要用这些纸币来支付k元,至少需要用多少张纸币?
纸币面额 | 数量 |
---|---|
1 | 3 |
2 | 1 |
5 | 2 |
10 | 1 |
20 | 1 |
50 | 3 |
100 | 5 |
3.2:解决思路
这个问题的目标函数是要使得纸币的数量最小,既然要纸币数量最小,那么我们在每一次选择的时候就要选择符合当前条件且面额最大的纸币。这样,最后的纸币数量才是最少的。
class Money:
def __init__(self,value,count):
self.value = value
self.count = count
# 创建money队列
def MoneyList():
money = []
mon1 = Money(1,3)
mon2 = Money(2,1)
mon3 = Money(5,2)
mon4 = Money(10,1)
mon5 = Money(20,1)
mon6 = Money(50,3)
mon7 = Money(100,5)
money.append(mon1)
money.append(mon2)
money.append(mon3)
money.append(mon4)
money.append(mon5)
money.append(mon6)
money.append(mon7)
return money
# 根据money的value排序
def Sort(list):
for i in range(len(list)):
for j in range(i+1,len(list)):
if list[i].value < list[j].value:
temp = list[i]
list[i] = list[j]
list[j] = temp
return list
# 选择最优方案
def Find_Best_Money(list,pay_money):
left_pay = pay_money # 剩余需要付的钱
result = []
for i in range(len(list)):
while list[i].value <= left_pay and list[i].count > 0:
result.append(list[i].value)
left_pay -= list[i].value
list[i].count -= 1
return result
def main():
money_list = MoneyList()
sort_list = Sort(money_list)
best_case = Find_Best_Money(sort_list,442)
print(best_case)
if __name__ == '__main__':
main()
对于纸币找零问题,贪心算法可能最终求出的解是不正确的,比如下面这组数据:
纸币面额 | 数量 |
---|---|
2 | 3 |
5 | 2 |
10 | 1 |
20 | 1 |
50 | 3 |
100 | 5 |
需要找零416元,但最后给出的答案却是:
需要100元4张
需要10元1张
需要5元1张
所以,这进一步验证了有些情况下,贪心算法无法给出最优解,但是它却是在想最优解靠近。
四:分糖果问题
4.1:问题描述
已知有一些孩子和糖果,每个孩子有需求因子need,每个糖果有大小size,只有当size >= need 时,糖果才可以满足孩子。 问:这些糖果最多可以满足多少孩子的需求?
4.2:解决思路
- 如果一个糖果无法满足需求因子为need的孩子,它必然满足不了需求因子>need的孩子
- 如果多个糖果可以满足一个需求因子为need的孩子,那么我们将这些糖果中size最小的一个分给该孩子,这样就可以将那些size更大的糖果分给need更大的孩子,进而就可以满足更多孩子的需求。
4.3:示例代码
child_need = [2,3,4,5,6]
sugar_size = [1,5,4,3,2]
child_need.sort() # 需求need排序
sugar_size.sort() # 大小size排序
total = 0
for i in range(len(child_need)):
for j in range(len(sugar_size)):
if sugar_size[j] >= child_need[i]: # 该糖果的size满足need
total += 1
sugar_size.pop(j)
break
print(total)