已發布·持續改進
貪婪演算法 指南 · 5/6
本章目前僅提供英文版。
Most greedy problems fall apart the moment you find the right ordering. The four problems below each exercise a different greedy rule. Before reading a solution, pick your rule and try to justify it in one sentence.
Each sensor in a plant has a time window [l, r] (both ends inclusive) in which its reading must be checked. An inspector does a round at chosen moments and checks every sensor whose window contains that moment. Find the fewest rounds that check every sensor, and their times.
Approach: sort windows by end time. The earliest-ending unchecked window must be inspected by its end anyway, so placing the round as late as possible, at r, covers the most later windows. As an exchange argument: moving the first round of an optimal plan to r never uncovers a window.
def min_check_times(windows):
times = []
for l, r in sorted(windows, key=lambda w: w[1]):
if not times or times[-1] < l: # last round happened before this window
times.append(r)
return times
print(min_check_times([(1, 4), (2, 6), (5, 8), (7, 9), (10, 12)])) # [4, 8, 12]A cart carries at most W kg. Each spice has a total value and weight, and you may scoop any portion of it. Find the maximum value you can load.
Approach: load spices in order of value per kilogram. When a spice is heavier than the remaining capacity, take just enough to fill the cart and stop. Swapping some expensive spice for a cheaper one can only lose value, so the rule is optimal. For exact results use fractions.Fraction, or compare ratios by cross-multiplication instead of division.
def max_cart_value(items, capacity):
"""items: list of (value, weight)."""
total = 0.0
for value, weight in sorted(items, key=lambda it: it[0] / it[1], reverse=True):
if capacity <= 0:
break
take = min(weight, capacity)
total += value * take / weight
capacity -= take
return total
print(max_cart_value([(120, 3), (100, 5), (60, 4)], 10)) # 250.0If items cannot be split (0/1 knapsack) this rule is wrong. With (60, 10), (100, 20), (120, 30) and capacity 50, ratio-greedy gets 160 while the optimum is 220.
Each task has a duration and a deadline, and you process one task at a time without breaks, starting at time 0. Maximize the number of tasks finished on time (late tasks are simply not done).
Approach: accept tasks in order of deadline, and whenever the running time overshoots the current deadline, drop the longest task accepted so far. Dropping the longest keeps the count the same while freeing the most time for later tasks. You need a max-heap, so store negated durations in Python.
import heapq
def max_on_time(tasks):
"""tasks: list of (duration, deadline)."""
heap, time = [], 0
for duration, deadline in sorted(tasks, key=lambda t: t[1]):
heapq.heappush(heap, -duration)
time += duration
if time > deadline:
time += heapq.heappop(heap) # negative, so this subtracts the longest duration
return len(heap)
print(max_on_time([(3, 4), (2, 5), (4, 7), (1, 8), (3, 9)])) # 4You want to merge n files of different sizes into one. Merging two files costs the sum of their sizes. Find the minimum total cost.
Approach: each file's size is paid once for every merge it takes part in (its depth in the merge tree), so this is exactly Huffman coding. Always merge the two smallest files.
import heapq
def min_merge_cost(sizes):
heap = list(sizes)
heapq.heapify(heap)
cost = 0
while len(heap) > 1:
a = heapq.heappop(heap)
b = heapq.heappop(heap)
cost += a + b
heapq.heappush(heap, a + b)
return cost
print(min_merge_cost([4, 3, 2, 6])) # 29Merging left to right (4+3, 7+2, 9+6) costs 7 + 9 + 15 = 31, while greedy does 2+3, 4+5, 6+9 for 5 + 9 + 15 = 29.
0 則留言
登入 · 登入後即可留言。
來留下第一則留言吧。