ตัวอย่างที่ 1 - Fibonacci
โจทย์: หา F(5) โดยสูตร F(n) = F(n-1) + F(n-2)
Visualizer: การเติมตาราง (Bottom-up)
คำนวณ i=2
เริ่มใหม่
Python Code
def fib_bottom_up(n):
# 1. สร้างตาราง (List) ขนาด n+1 ช่อง (เริ่มด้วย 0 ทั้งหมด)
dp = [0] * (n + 1)
# 2. ใส่ค่า Base Case (ถ้า n น้อยกว่า 2 ให้ return n เลย)
if n <= 1:
return n
dp[0] = 0
dp[1] = 1
# 3. วนลูปเติมค่าตั้งแต่ช่องที่ 2 จนถึง n
for i in range(2, n + 1):
dp[i] = dp[i-1] + dp[i-2] # สูตรเดิม แต่ใช้ค่าจากตาราง
return dp[n] # คืนค่าช่องสุดท้าย
print(fib_bottom_up(100)) # เร็วมากและไม่ Error!
Workshop 1 - Climbing Stairs
โจทย์บันได (Climbing Stairs)
มีบันได N ขั้น ขึ้นได้ทีละ 1 หรือ 2 ขั้น จะมีกี่วิธี?
ตาราง DP: dp[i] คือจำนวนวิธีเดินถึงขั้นที่ i
Base Case:
ขั้นที่ 1: มี 1 วิธี (เดิน 1) ➔ dp[1] = 1
ขั้นที่ 2: มี 2 วิธี (1+1, 2) ➔ dp[2] = 2
ความสัมพันธ์: dp[i] = dp[i-1] + dp[i-2] (เหมือน Fibonacci เป๊ะ!)
Python Code
def climb_stairs(n):
if n <= 2:
return n
# สร้างตารางรองรับ (บวก 1 เพื่อให้ index ตรงกับเลขชั้น)
dp = [0] * (n + 1)
# กำหนดค่าเริ่มต้น
dp[1] = 1
dp[2] = 2
# เริ่มวนลูปจากขั้นที่ 3
for i in range(3, n + 1):
dp[i] = dp[i-1] + dp[i-2]
return dp[n]
print(f"บันได 5 ขั้น มี {climb_stairs(5)} วิธี")
Level Up! - ปัญหาโลกแตกของตู้กดน้ำ (Coin Change)
โจทย์: มีเหรียญ 1, 3, 4 บาท ต้องการทอนเงิน 6 บาท ให้ใช้เหรียญ น้อยที่สุด กี่เหรียญ?
คิดแบบโลภมาก (Greedy)
หยิบเหรียญค่ามากสุดก่อน
4
+
1
+
1
รวม: 3 เหรียญ (ผิด! ไม่ใช่น้อยที่สุด)
คำตอบที่ดีที่สุด (DP)
มองหาผลรวมที่ใช้จำนวนเหรียญน้อยสุด
3
+
3
รวม: 2 เหรียญ (ถูกต้อง!)
การออกแบบตาราง DP
ให้ dp[i] เก็บจำนวนเหรียญที่น้อยที่สุด สำหรับเงิน i บาท
สูตร: dp[i] = min( dp[i], dp[i - coin] + 1 )
แปลว่า: ลองเอาเหรียญแต่ละแบบไปลบออก แล้วดูว่าเหลือเงินเท่าไหร่ เอาอันที่ใช้เหรียญน้อยที่สุด + 1 (เหรียญปัจจุบันที่เพิ่งหยิบ)
เงิน i (บาท)
0
1
2
3
4
5
6
dp[i] (จำนวนเหรียญ)
0
1
2
1
1
2
2
Python Code
def coin_change(coins, amount):
# สร้างตาราง และใส่ค่า Infinity ไว้ก่อนเพื่อหาตัวน้อยสุด
dp = [float('inf')] * (amount + 1)
dp[0] = 0
# วนลูปเงินตั้งแต่ 1 บาท ถึง amount
for i in range(1, amount + 1):
# ลองหยิบเหรียญแต่ละแบบ
for coin in coins:
if i - coin >= 0: # เช็คว่าเงินพอให้หยิบเหรียญนี้ไหม
# สูตร: min(ค่าเดิม, ค่าของเงินที่เหลือ + 1 เหรียญ)
dp[i] = min(dp[i], dp[i - coin] + 1)
# ถ้าค่าเป็น inf แปลว่าทอนไม่ได้ ให้ตอบ -1
return dp[amount] if dp[amount] != float('inf') else -1
print(coin_change([1, 3, 4], 6)) # Output: 2