Lecture 7 — Dijkstra & A*

Chương B** · đường *rẻ nhất* (gió · pin · cấm mềm) — không chỉ ít bước

Lecture 7 — Dijkstra & A*

Chương B · đường rẻ nhất (gió · pin · cấm mềm) — không chỉ ít bước


Khung 6 câu hỏi

# Câu hỏi Trả lời ngắn
1 Tại sao cần? Thực tế cạnh có giá khác nhau (xa, gió, cấm bay mềm, tốn pin) — BFS không đủ.
2 So với cái khác? Vs BFS: tối ưu theo cost. Vs A* vs Dijkstra: A* có \(h\) hướng về goal. Vs RL: \(h\) ≈ value; A* search có bảo đảm khi admissible.
3 Giải quyết gì & thế nào? Dijkstra pop theo \(g\); A* theo \(f=g+h\) với \(h\) admissible.
4 Kết quả ra sao? Path + cost*; dùng làm baseline / oracle / cost map cho reward.
5 Nên dùng khi nào? Đồ thị/lưới có cost; cần tối ưu hoặc gần tối ưu; thấp–trung bình chiều.
6 Không nên khi nào? Giá cạnh âm (Dijkstra); \(h\) inadmissible mà vẫn claim tối ưu; không gian liên tục cao chiều (→ RRT).

🖼️ Hình nhanh: Dijkstra = nước lan địa hình (chỗ rẻ ngập trước); A* = có la bàn dồn về goal.

Hình minh họa (seminar-ready)

Hình gốc hoặc minh họa cho ebook — không cắt từ slide Princeton. Dùng Present: bật Slide · F toàn màn.

Dijkstra lan đều · A* hướng về goal.
Dijkstra lan đều · A* hướng về goal.HiếuTC · gốc
  Dijkstra mở rộng:              A* mở rộng:
        · · · · ·
     · · · · · · ·                  · · ·
    · · · S · · · ·      S · · · · · · · ► G
     · · · · · · ·                  · · ·
       · · · · ·  ► G
   (tròn đều, tốn nút)         (giọt nước về goal, tiết kiệm)

  f = g + h     g = cost-to-come     h = ước lượng cost-to-go

0. Mục tiêu học

  1. Phân biệt Dijkstra và A* (pop theo \(g\) vs \(f=g+h\)).
  2. Định nghĩa heuristic admissible / consistent; hệ quả tối ưu.
  3. Liên hệ \(h\) với value function trong RL.
  4. Chạy A* trên lưới cost (ô đắt = gió/cấm mềm); đọc cost* và path.

1. Trực giác — nói bằng lời thường

Trên bản đồ đồi chè, “mét đường chim bay” thường là lời nói dối dễ thương: leo dốc và ngược gió đắt pin hơn đi ngang đường đồng mức.

  • Một ô “xa” và một ô “gió mạnh / leo sườn / cấm bay mềm” không cùng giá. BFS chỉ đếm bước — sẽ đi xuyên vùng gió nếu ngắn hơn vài ô.
  • Dijkstra = luôn mở rộng đỉnh đang có tổng giá rẻ nhất từ start. Như nước lan trên địa hình: chỗ trũng (rẻ) ngập trước.
  • A* = Dijkstra có la bàn: ngoài \(g(n)\) đã đi, cộng ước lượng còn lại \(h(n)\), ưu tiên \(f=g+h\) nhỏ. Loang hình giọt nước dồn về goal — ít đỉnh hơn hẳn.

🇻🇳 Chuyện thật (sân A): Quét phủ đồi chè Thái Nguyên / Mộc Châu: cạnh đi ngược gió sườn hoặc leo thẳng dốc phải mang cost cao hơn cạnh đi ngang đường đồng mức — dù mét ngắn hơn.
Dijkstra / A* với \(c(e)\) gắn gió–leo–pin sẽ né “đường ngắn mà chết pin giữa thửa”; BFS đếm bước thì vẫn lao vào.
Heuristic \(h\) admissible (không ước quá thấp chi phí còn lại) giữ A* vừa tối ưu vừa ít mở nút.
Chốt: cost cạnh ≠ mét thuần; trên chuyến bay, path tối ưu năng lượng / gió đã được mã hóa trong \(g\) và \(h\). Chi tiết sân: ../00C.


2. Cốt lõi kỹ thuật

2.1 Dijkstra

  • Priority queue theo \(g\); mỗi đỉnh chốt (pop) một lần với giá tối ưu.
  • Yêu cầu giá cạnh không âm.
  • \(O((|V|+|E|)\log|V|)\) với heap.

2.2 A* và admissibility

\[ f(n)=g(n)+h(n) \]

  • \(h\) admissible: không bao giờ ước lượng quá cost thật còn lại → A* tối ưu.
    Ví dụ: Euclid / Manhattan (với giá bước ≥ 1 phù hợp) ≤ đường thật giữa vật cản.
  • \(h\) consistent (tam giác): không phải mở lại đỉnh.
  • \(h=0\) ⇒ A* = Dijkstra (chậm, chắc).
  • \(h\) quá lớn (inadmissible) ⇒ greedy, có thể lệch tối ưu.
  • Weighted A*: \(f=g+w h\), \(w>1\) — nút vặn tốc độ ↔ tối ưu.

2.3 So sánh nhanh (bảng)

BFS Dijkstra A*
Tối ưu số cạnh (cạnh đều) cost* (≥0) cost* nếu \(h\) admissible
Hướng goal không không có \(h\)
RL analogy uniform cost steps cost-to-come \(h\approx V\) dẫn đường

2.4 Sơ đồ quyết định chọn thuật toán

  Cạnh đồng giá? ──yes──► BFS
       │ no
       ▼
  Cần hướng goal / ít mở nút? ──no──► Dijkstra
       │ yes
       ▼
  Có h admissible? ──yes──► A*     ──no──► đừng claim tối ưu
       │
       ▼ cao chiều liên tục? ──► RRT (Lec 8)

3. Demo — A* lưới có giá địa hình

"""A* trên lưới 5x5; ô giá 9 = vùng đắt (gió/cấm mềm).
So với BFS: đường có thể dài hơn theo số ô nhưng rẻ hơn theo cost.
"""
import heapq

cost = [
    [1, 1, 1, 9, 1],
    [1, 9, 1, 9, 1],
    [1, 9, 1, 1, 1],
    [1, 1, 1, 9, 1],
    [9, 9, 1, 1, 1],
]
R = C = 5
start, goal = (0, 0), (4, 4)

def h(n):
    # Manhattan: admissible trên lưới 4-hướng khi mọi bước cost ≥ 1
    return abs(n[0] - goal[0]) + abs(n[1] - goal[1])

g = {start: 0.0}
parent = {start: None}
pq = [(h(start), start)]  # f = g+h; g(start)=0

while pq:
    f_cur, cur = heapq.heappop(pq)
    if cur == goal:
        break
    for dr, dc in [(1, 0), (-1, 0), (0, 1), (0, -1)]:
        nb = (cur[0] + dr, cur[1] + dc)
        if not (0 <= nb[0] < R and 0 <= nb[1] < C):
            continue
        ng = g[cur] + cost[nb[0]][nb[1]]
        if ng < g.get(nb, float("inf")):
            g[nb] = ng
            parent[nb] = cur
            heapq.heappush(pq, (ng + h(nb), nb))

path, n = [], goal
while n is not None:
    path.append(n)
    n = parent[n]
path.reverse()
print("Cost* =", g[goal])
print("Path  =", path)
print("Gợi ý: đổi vài ô 9→1 và chạy lại — đường sẽ 'đổi ý' (cost shaping).")

🧪 Kỳ vọng demo:
- Cost* là tổng giá ô trên path (không phải chỉ số bước).
- Path thường tránh cụm ô 9 dù có thể dài hơn vài ô so với đường “ngắn hình học”.
- Đổi 9→1 → path đổi ý — đúng cảm giác cost map gió/pin.
★ Nếu dùng \(h\) inadmissible (ví dụ phóng đại Manhattan × 10) rồi vẫn nói “tối ưu” → sai.


4. Gắn RL–UAV / path-planning đa mục tiêu của bạn

  • \(g\) = cost-to-come, \(h\) = ước lượng cost-to-go → \(h\) là value function xấp xỉ. A* = search dẫn đường bởi value — cùng dòng máu heuristic MCTS/AlphaZero.
  • Hướng tự nhiên: học \(h\) bằng mạng rồi cắm A* — bảo đảm search + tốc độ học.
  • Cost map (gió, cấm mềm, năng lượng, ô chưa phủ) = bản rời rạc của reward/cost bạn shaping trong RL.
  • Dùng A* làm oracle / baseline trên cùng map trước khi claim RL tốt hơn.
  • Weighted A* khi cần path nhanh cho replan realtime dưới gió đổi.

5. Ưu / nhược (câu 5–6)

✅ Nên ❌ Không Năng lượng / gió / phủ
Dijkstra Cost map, không có \(h\) tốt Cạnh âm Baseline cost*
A* \(h\) admissible (Manhattan/Euclid phù hợp) Claim tối ưu khi \(h\) phóng đại Ít nút hơn khi phủ rộng
Weighted A* Replan nhanh Cần chứng minh tối ưu chặt Trade-off tốc độ–pin path
vs RL Oracle trên map tĩnh Thay thế policy đa map RL amortize phân phối map

6. Lỗi thường gặp

  • ⚠️ Dùng heuristic không admissible rồi vẫn khẳng định “A* luôn tối ưu”.
  • ⚠️ Nhầm “đường ngắn theo số ô” với “đường rẻ theo cost map” — đó là BFS vs Dijkstra/A*.
  • ⚠️ Bỏ giá cạnh âm vào Dijkstra (hoặc cost âm ngầm trong reward map) rồi tin kết quả.

7. Checklist

  1. Điều kiện để Dijkstra đúng? Vì sao cần giá cạnh ≥ 0?
  2. Admissible khác consistent chỗ nào — hệ quả thuật toán?
  3. Giải thích “A* = Dijkstra + value function” bằng ngôn ngữ RL?
  4. Trên cost map gió, vì sao path A* có thể dài hơn BFS theo số ô?

Nhớ một câu: A* = Dijkstra có la bàn \(h\); tối ưu khi \(h\) admissible — và \(h\) chính là value xấp xỉ.

🔗 Sang bài sau mang theo: Lưới/A* chết ở chiều cao liên tục → Lec 8 RRT: sample → nearest → steer → collision check.


Trước: Lec06 · Sau: Lec08 — RRT