贪心算法概念
贪心:把整体问题分解成多个步骤,在每个步骤都选取当前步骤的最优方案,直至所有步骤结束;每个步骤不会影响后续步骤。
核心性质:每次采用局部最优,最终结果就全局最优(题目满足上述核心性质,则可以采用贪心进行求解)。
举个例子,最少硬币支付问题
1.假设有三种硬币:1元、2元、5元,数量不限,现在需要支付M元,要求硬币数目最少,应该如何支付?
我们容易想到,如果要保证硬币尽可能少,得尽可能选择大面值的硬币。该题采用局部最优就能得到全局最优,符合贪心的性质。
2.如果把硬币面值改成1元、2元、4元、5元、6元,现在支付9元,按照贪心: 6+2+1,需要3个硬币,但是最优结果:4+5,该题局部最优不能得到全局最优,不符合贪心的性质。
如何判断是否能用贪心?
1、最优子结构性质:当一个问题的最优解包含子问题的最优解,则称之为具有最优子结构性质。
2、贪心性质选择:可以通过局部最优的选择得到全局最优
那具体到解问题的时候如何做呢?
1、积累各种类型的贪心解题方法
2、举反例(证明不能用贪心,例如上题2)
现在来做一道贪心算法相关的题目吧!
一
题目
元旦快到了,校学生会让乐乐负责新年晚会的纪念品发放工作。为使得参加晚会的同学所获得的纪念品价值相对均衡,他要把购来的纪念品根据价格进行分组,但每组最多只能包括两件纪念品,并且每组纪念品的价格之和不能超过一个给定的整数。为了保证在尽量短的时间内发完所有纪念品,乐乐希望分组的数目最少。你的任务是写一个程序,找出所有分组方案中分组数最少的一种,输出最少的分组数目。
输入描述
第1行包括一个整数w (80 <w<200),为每组纪念品价格之和的上限。
第2行为一个整数n (1<n <30000),表示购来的纪念品的总件数。
第3~n+2行每行包含一个正整数ai (5≤ai ≤ w),表示所对应纪念品的价格。
输出描述
输出—行,包含—个整数,即最少的分组数目。
输入输出示例
输入
100
9
90
20
20
30
50
60
70
80
90
输出
6
思路
以示例为例,我把这些数字排序
20
20
30
50
60
70
80
90
90
每一次容纳的价格不能超过100且每组最多只能包括两件纪念品,那么我们考虑每一个价格更贵的纪念品能不能容纳一个价格较低的一个纪念品,如果能则合为一组。不能就大的那一件礼物单独为一组,示例中两个90的肯定是单独为一组。80的可以和20的凑等等,最后分成6组。
所以策略呢其实是每一个大的去拿一个小的跟它配,那么这个为什么是最优的呢?
因为价格大的礼物要不单独为一组,要么就拿一个小的给它配,这样肯定是不会浪费的,和第二大的去配浪费更大,这样去考虑,其实每一步都是最优的。
代码
w = int(input())
n = int(input())
a = []
for i in range(n):
a.append(int(input()))
a.sort() # 给a数组排序
ans = 0 # 记组数
l, r = 0, n - 1 # 分别取两个端点
while True:
if l == r: # 如果相等,说明剩最后一个礼物,单独为一组
ans += 1
break
if l > r: # l加1和r减1可能会互相岔开,一但发生则说明分组结束
break
if a[l] + a[r] <= w: # 小于w则说明两者可以合为一组
ans += 1
l += 1
r -= 1
else: # 不能合为一组,则价格大的单独为一组,再找次大的配
r -= 1
ans += 1
print(ans)
看到这里了,点个免费的赞吧!