On this page
Greedy Algorithms
แก้ปัญหาด้วยการเลือก "ดีที่สุดตอนนี้" ทุกขั้น — เร็วและง่าย แต่ต้องรู้ว่าเมื่อไรใช้ไม่ได้
greedy algorithm แก้ปัญหาด้วยการเลือกตัวเลือกที่ดีที่สุด ณ ตอนนั้นทุกขั้น โดยไม่ย้อนคิด เร็วและเขียนง่าย แต่ใช้ได้เฉพาะปัญหาบางแบบ — สำคัญที่ต้องรู้ว่าเมื่อไรใช้ได้และเมื่อไรไม่ได้
ตัวอย่าง: ทอนเงินจำนวนเหรียญน้อยสุด
เลือกเหรียญใหญ่สุดที่ใช้ได้ก่อนเสมอ — greedy ใช้ได้กับชุดเหรียญมาตรฐาน
def make_change(amount, coins):
coins = sorted(coins, reverse=True) # ใหญ่ไปเล็ก
result = []
for coin in coins:
while amount >= coin:
amount -= coin # เลือกเหรียญใหญ่สุดที่ใช้ได้
result.append(coin)
return result
print(make_change(63, [1, 5, 10, 20])) # [20,20,20,1,1,1]ตัวอย่าง: activity selection
เลือกกิจกรรมให้ได้มากที่สุดโดยไม่ทับเวลากัน — greedy: เลือกตัวที่ "จบก่อน" เสมอ
def max_activities(activities):
# activities = [(start, end), ...]
activities.sort(key=lambda a: a[1]) # เรียงตามเวลาจบ
count, last_end = 0, 0
for start, end in activities:
if start >= last_end: # ไม่ทับ
count += 1
last_end = end
return count
print(max_activities([(1, 3), (2, 5), (4, 6), (6, 8)])) # 3greedy ไม่ได้ผลเสมอ
บางปัญหา greedy ให้คำตอบผิด เช่นทอนเงินด้วยชุดเหรียญแปลก ๆ — ต้องใช้ DP แทน
# coins = [1, 3, 4], ทอน 6
# greedy: 4 + 1 + 1 = 3 เหรียญ (ผิด!)
# คำตอบจริง: 3 + 3 = 2 เหรียญ (DP หาเจอ)greedy ใช้ได้ก็ต่อเมื่อ "การเลือกดีที่สุดตอนนี้ นำไปสู่คำตอบที่ดีที่สุดโดยรวม" (greedy choice property) ถ้าไม่แน่ใจ อย่าเพิ่งเชื่อ greedy — ลองหา counterexample หรือใช้ DP เทียบ เพราะ greedy ที่ผิดจะดูเหมือนถูกในตัวอย่างง่าย ๆ
สรุปหัวข้อนี้
- greedy = เลือกดีที่สุดตอนนี้ทุกขั้น ไม่ย้อนคิด — เร็ว เขียนง่าย
- ใช้ได้: ทอนเงิน(ชุดมาตรฐาน), activity selection, interval
- ไม่ได้เสมอ — บางปัญหาต้องใช้ DP (เช่นทอนเงินชุดแปลก)
- ต้องมั่นใจว่า 'ดีตอนนี้ → ดีรวม' ก่อนใช้ greedy
1) เขียนทอนเงินแบบ greedy 2) แก้ activity selection 3) หา counterexample ที่ greedy ทอนเงินผิด (coins=[1,3,4]) 4) อธิบาย greedy choice property ด้วยคำตัวเอง