1. Trang chủ
  2. » Trung học cơ sở - phổ thông

CÁC PHƯƠNG PHÁP tìm KIẾM TRÊN đồ THỊ

21 19 0

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 21
Dung lượng 93,43 KB

Nội dung

Một bài toán quan trọng trong lí thuyết đồ thị là bài toán duyệt tất cả các đỉnh có thể đến được từ một đỉnh xuất phát nào đó. Vấn đề này đưa về một bài toán liệt kê mà yêu cầu của nó là không được bỏ sót hay lặp lại bất kì đỉnh nào. Chính vì vậy mà ta phải xây dựng những thuật toán cho phép duyệt một cách hệ thống các đỉnh, những thuật toán như vậy gọi là những thuật toán tìm kiếm trên đồ thị (graph traversal). Ta quan tâm đến hai thuật toán cơ bản nhất: thuật toán tìm kiếm theo chiều sâu và thuật toán tìm kiếm theo chiều rộng. 1. Thuật toán tìm kiếm theo chiều sâu : a. Thuật toán tìm kiếm theo chiều sâu: Ý tưởng: Tư tưởng của thuật toán tìm kiếm theo chiều sâu (DepthFirst Search DFS) có thể trình bày như sau: Trước hết, dĩ nhiên đỉnh s đến được từ s, tiếp theo, với mọi cung (s, x) của đồ thị thì x cũng sẽ đến được từ s. Với mỗi đỉnh x đó thì tất nhiên những đỉnh y nối từ x cũng đến được từ s... Điều đó gợi ý cho ta viết một thủ tục đệ quy DFSVisit(u) mô tả việc duyệt từ đỉnh u bằng cách thăm đỉnh u và tiếp tục quá trình duyệt DFSVisit(v) với v là một đỉnh chưa thăm nối từ u . Kĩ thuật đánh dấu được sử dụng để tránh việc liệt kê lặp các đỉnh: Khởi tạo availv:=true, vV, mỗi lần thăm một đỉnh, ta đánh dấu đỉnh đó lại (availv:=false) để các bước duyệt đệ quy kế tiếp không duyệt lại đỉnh đó nữa.

CÁC PHƯƠNG PHÁP TÌM KIẾM TRÊN ĐỒ THỊ Một tốn quan trọng lí thuyết đồ thị tốn duyệt tất đỉnh đến từ đỉnh xuất phát Vấn đề đưa toán liệt kê mà yêu cầu khơng bỏ sót hay lặp lại đỉnh Chính mà ta phải xây dựng thuật toán cho phép duyệt cách hệ thống đỉnh, thuật toán gọi thuật tốn tìm kiếm đồ thị (graph traversal) Ta quan tâm đến hai thuật toán nhất: thuật tốn tìm kiếm theo chiều sâu thuật tốn tìm kiếm theo chiều rộng Thuật tốn tìm kiếm theo chiều sâu : a Thuật tốn tìm kiếm theo chiều sâu: Ý tưởng: Tư tưởng thuật toán tìm kiếm theo chiều sâu (Depth-First Search - DFS) trình bày sau: Trước hết, dĩ nhiên đỉnh s đến từ s, tiếp theo, với cung (s, x) đồ thị x đến từ s Với đỉnh x tất nhiên đỉnh y nối từ x đến từ s Điều gợi ý cho ta viết thủ tục đệ quy DFSVisit(u) mô tả việc duyệt từ đỉnh u cách thăm đỉnh u tiếp tục trình duyệt DFSVisit(v) với v đỉnh chưa thăm nối từ u Kĩ thuật đánh dấu sử dụng để tránh việc liệt kê lặp đỉnh: Khởi tạo avail[v]:=true, ∀v∈V, lần thăm đỉnh, ta đánh dấu đỉnh lại (avail[v]:=false) để bước duyệt đệ quy khơng duyệt lại đỉnh Thuật tốn: procedure DFSVisit(u ∈ V); //Thuật tốn tìm kiếm theo chiều sâu từ đỉnh u begin avail[u] := False; //avail[u] = False ⇔ u thăm Output ← u; //Liệt kê u for ∀v ∈ V:(u, v)∈ E //Duyệt đỉnh v chưa thăm nối từ u if avail[v] then DFSVisit(v); end; begin //Chương trình Input → Đồ thị G for ∀v ∈ V avail[v] := True; //Đánh dấu đỉnh chưa thăm DFSVisit(s); end b Thuật tốn tìm đường theo DFS: Bài tốn tìm đường đi: Cho đồ thị G=(V,E) hai đỉnh s, t ∈ V Nhắc lại định nghĩa đường đi: Một dãy đỉnh: P= (∀i: (pi-1, pi) ∈ E) gọi đường từ s tới t, đường gồm k+1 đỉnh p0 , p1, …, pk 1 cạnh (p0, p1), (p1, p2), …,(pk-1, pk) Đỉnh s gọi đỉnh đầu đỉnh t gọi đỉnh cuối đường Nếu tồn đường từ s tới t, ta nói s đến t t đến từ s: s t Thuật toán: Để lưu lại đường từ đỉnh xuất phát s, thủ tục DFSVisit(u), trước gọi đệ quy DFSVisit(v) với v đỉnh chưa thăm nối từ u chưa đánh dấu), ta lưu lại vết đường từ u tới v cách đặt trace[v]:=u, tức trace[v] lưu lại đỉnh liền trước v đường từ s tới v Khi thuật toán DFS kết thúc, đường từ s tới t là: procedure DFSVisit(u∈V); //Thuật tốn tìm kiếm theo chiều sâu từ đỉnh u begin avail[u] := False; //avail[u] = False ⇔ u thăm for ∀ v∈ V:(u, v)∈ E //Duyệt đỉnh v chưa thăm nối từ u if avail[v] then begin trace[v] := u; //Lưu vết đường đi, đỉnh liền trước v đường từ s tới v u DFSVisit(v); //Gọi đệ quy để tìm kiếm theo chiều sâu từ đỉnh v end; end; begin / /Chương trình Input → Đồ thị G, đỉnh xuất phát s, đỉnh đích t; for ∀v ∈ V avail[v] := True; //Đánh dấu đỉnh chưa thăm DFSVisit(s); if avail[t] then //s đến t «Truy theo vết từ t để tìm đường từ s tới t»; end Có thể khơng cần mảng đánh dấu avail[1 … n] mà dùng mảng trace[1 … n] để đánh dấu: Khởi tạo phần tử mảng trace[1 … n] là: Trace[s]≠0 Trace[v]=0, ∀v≠s Khi điều kiện để đỉnh v chưa thăm trace[v] = 0, từ đỉnh u thăm đỉnh v, phép gán trace[v]= u kiêm công việc đánh dấu v thăm (trace[v] ≠ 0) Tính chất BFS Nếu ta xếp danh sách kề đỉnh theo thứ tự tăng dần thuật tốn DFS ln trả đường có thứ tự từ điển nhỏ số tất đường từ s tới tới t c Thuật toán duyệt đồ thị theo DFS Cài đặt ứng dụng thuật toán DFS để liệt kê đỉnh đến từ đỉnh Thuật toán DFS dùng để duyệt qua đỉnh cạnh đồ thị viết sau: procedure DFSVisit(u∈V); //Thuật tốn tìm kiếm theo chiều sâu từ đỉnh u begin 2 Time := Time + 1; d[u] := Time; //Thời điểm duyệt đến u Output ← u; //Liệt kê u for ∀v∈V:(u, v) ∈E //Duyệt đỉnh v nối từ u if d[v] = then DFSVisit(v); //Nếu v chưa thăm, gọi đệ quy để tìm // kiếm theo chiều sâu từ đỉnh v Time := Time + 1; f[u] := Time; //Thời điểm duyệt xong u end; begin //Chương trình Input → Đồ thị G for ∀v∈V d[v] := 0; //Mọi đỉnh chưa duyệt đến Time := 0; for ∀v∈V if d[v] = then DFSVisit(v); end Thời gian thực giải thuật DFS đánh giá số lần gọi thủ tục DFSVisit (|V| lần) cộng với số lần thực vịng lặp for bên thủ tục DFSVisit Chính vậy: • Nếu đồ thị biểu diễn danh sách kề danh sách liên thuộc, vòng lặp for bên thủ tục DFSVisit (xét tổng thể chương trình) duyệt qua tất cạnh đồ thị (mỗi cạnh hai lần đồ thị vô hướng, cạnh lần đồ thị có hướng) Trong trường hợp này, thời gian thực giải thuật DFS Θ(|V| + |E|) • Nếu đồ thị biểu diễn ma trận kề, vòng lặp for bên thủ tục DFSVisit phải duyệt qua tất đỉnh … n Trong trường hợp thời gian thực giải thuật DFS Θ(|V| + |V|2) = Θ(|V|2) • Nếu đồ thị biểu diễn danh sách cạnh, vòng lặp for bên thủ tục DFSVisit phải duyệt qua tất danh sách cạnh lần thực thủ tục Trong trường hợp thời gian thực giải thuật DFS Θ(|V||E|) Thuật tốn tìm kiếm theo chiều rộng: a Thuật tốn tìm kiếm theo chiều rộng Ý tưởng: s u1s v1s v2s u2s … … Thăm trước tất đỉnh v Thăm sau tất đỉnh u Tư tưởng thuật tốn tìm kiếm theo chiều rộng (Breadth-First Search – 3 BFS) “lập lịch” duyệt đỉnh Việc thăm đỉnh lên lịch duyệt đỉnh nối từ cho thứ tự duyệt ưu tiên chiều rộng (đỉnh gần đỉnh xuất phát s duyệt trước) Đầu tiên ta thăm đỉnh s Việc thăm đỉnh s phát sinh thứ tự thăm đỉnh u1, u2, … nối từ s (những đỉnh gần s nhất) Tiếp theo ta thăm đỉnh u1, thăm đỉnh u1 lại phát sinh yêu cầu thăm đỉnh r1, r2, … nối từ u1 Nhưng rõ ràng đỉnh r “xa” s đỉnh u nên chúng thăm tất đỉnh u thăm Tức thứ tự duyệt đỉnh là: s, u1, u2, … , r1, r2, … Thuật tốn tìm kiếm theo chiều rộng sử dụng danh sách để chứa đỉnh “chờ” thăm Tại bước, ta thăm đỉnh đầu danh sách, loại khỏi danh sách cho đỉnh chưa “xếp hàng” kề với xếp hàng thêm vào cuối danh sách Thuật toán kết thúc danh sách rỗng Vì nguyên tắc vào trước trước, danh sách chứa đỉnh chờ thăm tổ chức dạng hàng đợi (Queue): Nếu ta có Queue hàng đợi với thủ tục Push(r) để đẩy đỉnh r vào hàng đợi hàm Pop trả đỉnh lấy từ hàng đợi thuật tốn BFS viết sau: Thuật toán: Queue := (s); //Khởi tạo hàng đợi gồm đỉnh s for ∀v∈V avail[v] := True; avail[s] := False; //Đánh dấu có đỉnh s xếp hàng repeat //Lặp tới hàng đợi rỗng u := Pop; //Lấy từ hàng đợi đỉnh u Output ← u; //Liệt kê u for ∀v∈V:avail[v] and (u, v) ∈ E //Xét đỉnh v kề u chưa //đẩy vào hàng đợi begin Push(v); //Đẩy v vào hàng đợi avail[v] := False; //Đánh dấu v xếp hàng end; until Queue = Ø; Thuật tốn tìm đường theo BFS: Queue := (s); //Khởi tạo hàng đợi gồm đỉnh s for ∀v∈V avail[v] := True; avail[s] := False; //Đánh dấu có đỉnh s xếp hàng repeat //Lặp tới hàng đợi rỗng u := Pop; //Lấy từ hàng đợi đỉnh u for ∀v∈V:avail[v] and (u, v) ∈ E //Xét đỉnh v kề u chưa //đẩy vào hàng đợi begin trace[v] := u; //Lưu vết đường Push(v); //Đẩy v vào hàng đợi avail[v] := False; //Đánh dấu v xếp hàng end; until Queue = Ø; 4 if avail[t] then //s tới t «Truy theo vết từ t để tìm đường từ s tới t»; Tương tự thuật tốn tìm kiếm theo chiều sâu, ta dùng mảng Trace[1 … n] kiêm ln chức đánh dấu Tính chất BFS Thuật tốn BFS ln trả đường qua cạnh số tất đường từ s tới t Nếu ta xếp danh sách kề đỉnh theo thứ tự tăng dần có nhiều đường từ s tới t qua cạnh thuật tốn BFS trả đường có thứ tự từ điển nhỏ số đường c Thuật tốn duyệt đồ thị theo BFS Tương tự thuật toán DFS, thực tế, thuật toán BFS dùng để xác định thứ tự đỉnh đồ thị viết theo mơ hình sau: procedure BFSVisit(s∈V); begin Queue := (s); //Khởi tạo hàng đợi gồm đỉnh s Time := Time + 1; d[s] := Time; //Duyệt đến đỉnh s repeat //Lặp tới hàng đợi rỗng u := Pop; //Lấy từ hàng đợi đỉnh u Time := Time+1; F[u]:=Time; //Ghi nhận thời điểm duyệt xong đỉnh u Output ← u; //Liệt kê u for ∀v∈V:(u, v) ∈E //Xét đỉnh v kề u if d[v] = then //Nếu v chưa duyệt đến begin Push(v); //Đẩy v vào hàng đợi Time := Time + 1; d[v] := Time; //Ghi nhận thời điểm duyệt đến đỉnh v end; until Queue = Ø; end; begin //Chương trình Input → Đồ thị G; for ∀v∈V d[v] := 0; //Mọi đỉnh chưa duyệt đến Time := 0; for ∀v∈V if d[v]=0 then BFSVisit(v); end Thời gian thực giải thuật BFS tương tự DFS, Θ(|V| + |E|) đồ thị biểu diễn danh sách kề danh sách liên thuộc, Θ(|V|2) đồ thị biểu diễn ma trận kề, Θ(|V||E|) đồ thị biểu diễn danh sách cạnh 5 Bài tập: Bài 1: Mê cung hình chữ nhật kích thước m×n gồm vng đơn vị (m, n ≤ 1000) Trên ô ghi ba kí tự: • O: Nếu an tồn • X: Nếu có cạm bẫy • E: Nếu có nhà thám hiểm đứng Duy có ghi chữ E Nhà thám hiểm từ sang số ô chung cạnh với ô đứng Một cách thoát khỏi mê cung hành trình qua an tồn ô biên Hãy giúp cho nhà thám hiểm hành trình khỏi mê cung qua ô Dữ liệu vào từ tệp văn MECUNG.INP • Dịng 1: Ghi m, n (1

Ngày đăng: 09/03/2021, 14:22

TỪ KHÓA LIÊN QUAN

TÀI LIỆU CÙNG NGƯỜI DÙNG

TÀI LIỆU LIÊN QUAN

w