“贪心”的含义
贪心算法(Greedy Algorithm)是一种常见的算法设计策略,用于解决优化问题。在贪心算法中,每一步都采取当前状态下最优的选择,而不考虑该选择对未来的影响。这种策略在每一步都寻找局部最优解,希望通过一系列局部最优解的组合来达到全局最优解。
贪心算法的基本思想是通过不断地做出局部最优选择,直到达到全局最优解。然而,由于它只关注当前步骤的最优解,而不是考虑全局的长远影响,所以并不是所有问题都适合使用贪心算法。在某些情况下,贪心算法可能会得到次优解或者根本无法得到正确解。
要使用贪心算法解决问题,通常需要满足以下两个关键性质:
-
贪心选择性质(Greedy Choice Property):在每一步都做出局部最优选择,即当前情况下看起来最好的选择。
-
最优子结构性质(Optimal Substructure Property):问题的全局最优解可以通过一系列局部最优解来达到。
常见的应用贪心算法的问题包括找零钱问题、活动选择问题、背包问题(部分情况下)、最短路径问题(部分情况下)等。贪心算法在某些情况下可以高效地求解问题,但在一些复杂的问题中,可能需要结合其他算法或策略来得到正确的解答。
找零问题:
问题描述:
假设有以下硬币面额:1元、5元、10元、25元。现在需要找零32元,问如何找零使得硬币数量最少?
使用贪心算法的思路是每次选择最大面额的硬币,直到剩余金额为0。在这个示例中,可以按以下步骤进行:
- 找一个面额最大的硬币,小于等于目标金额:25元,剩余金额为32 - 25 = 7元。
- 继续找一个面额最大的硬币,小于等于剩余金额:5元,剩余金额为7 - 5 = 2元。
- 找一个面额最大的硬币,小于等于剩余金额:1元,剩余金额为2 - 1 = 1元。
- 找一个面额最大的硬币,小于等于剩余金额:1元,剩余金额为1 - 1 = 0元。
在这个例子中,使用了2个1元硬币、1个5元硬币和1个25元硬币,总共4个硬币,实现了找零32元。这种情况下贪心算法得到了最优解,但并非所有情况下贪心算法都能得到最优解。
需要注意的是,贪心算法并不适用于任何情况,因为它只关注局部最优解,可能会在某些情况下导致次优解。在硬币面额不是常见的 1、5、10、25 这种特殊情况下,贪心算法可能无法得到最优解。
代码实现:
def coin_change_greedy(coins, amount):
coins.sort(reverse=True) # 从大到小排序
num_coins = 0
i = 0
while amount > 0 and i < len(coins):
if coins[i] <= amount:
num_coins += 1
amount -= coins[i]
else:
i += 1
if amount == 0:
return num_coins
else:
return -1 # 无法找零
# 示例硬币面额和目标金额
coins = [1, 5, 10, 25]
amount = 32
result = coin_change_greedy(coins, amount)
if result != -1:
print(f"最少需要 {result} 枚硬币来找零 {amount} 元。")
else:
print("无法找零。")
活动策划问题:
问题描述:
假设你参加了一个会议,会议的日程安排如下:
活动 | 开始时间 | 结束时间 |
---|---|---|
A | 1 | 4 |
B | 3 | 5 |
C | 0 | 6 |
D | 5 | 7 |
E | 3 | 8 |
F | 5 | 9 |
G | 6 | 10 |
H | 8 | 11 |
I | 8 | 12 |
J | 2 | 13 |
K | 12 | 14 |
现在的问题是,如何选择一组活动,使得你能够参加尽可能多的活动,而且这些活动的时间段不能相互重叠?
使用贪心算法解决这个问题的思路是,首先按照活动的结束时间从小到大对活动进行排序。然后从第一个活动开始,选择结束时间最早的活动,并且确保所选活动的时间段不与之前选择的活动相重叠。在这个例子中,按照结束时间排序后的活动序列是:
活动 | 开始时间 | 结束时间 |
---|---|---|
C | 0 | 6 |
A | 1 | 4 |
J | 2 | 13 |
B | 3 | 5 |
E | 3 | 8 |
D | 5 | 7 |
F | 5 | 9 |
G | 6 | 10 |
H | 8 | 11 |
I | 8 | 12 |
K | 12 | 14 |
使用贪心算法,按照上述排序选择活动,你可以参加的活动数量最多,共有 8 个活动:C、A、B、D、G、H、I、K。
这个例子演示了活动选择问题中贪心算法的应用,通过每次选择结束时间最早的活动来获得局部最优解,最终达到全局最优解,即参加尽可能多的活动。
代码实现:
def activity_selection(start_times, finish_times):
n = len(start_times)
activities = list(zip(start_times, finish_times))
activities.sort(key=lambda x: x[1]) # 按结束时间排序
selected_activities = [activities[0]]
last_finish_time = activities[0][1]
for i in range(1, n):
if activities[i][0] >= last_finish_time:
selected_activities.append(activities[i])
last_finish_time = activities[i][1]
return selected_activities
# 示例活动的开始时间和结束时间
start_times = [1, 3, 0, 5, 8, 5, 6, 8, 8, 2, 12]
finish_times = [4, 5, 6, 7, 9, 9, 10, 11, 12, 13, 14]
selected = activity_selection(start_times, finish_times)
print("选择的活动:")
for activity in selected:
print(f"开始时间:{activity[0]}, 结束时间:{activity[1]}")
背包问题将会和后期智能算法一起讲解