Thuật toán đồ thị có hướng và chu trình

6 2.1K 44
Thuật toán đồ thị có hướng và chu trình

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

Thông tin tài liệu

Thuật toán đồ thị có hướng và chu trình

Những thuật toán hiệu quả trên đồ thị hướng phi chu trìnhNgô Quốc HoànĐồ thị là một lĩnh vực quan trọng trongtoán học rời rạc nhiều ứng dụng trong việc giải các bài toántin học cũng như trong cuộc sống. Đồ thị hướng phi chu trình làmột trường hợp đặc biệt của đồ thị. Trong bài viết này chúng tôixin trình bày với các bạn những thuật toán hết sức hiệu quả trênđồ thị hướng phi chu trình những bài toán ứng dụng rất lýthú. Trước hết ta xét một thuật toánquan trọng sau: 1. Thuật toán đánh số Định lý: Giả sử G là đồ thị hướngphi chu trình, khi đó các đỉnh của nó thể đánh số sao cho mỗicung của đồ thị chỉ hướng từ đỉnh chỉ số nhỏ hơn đến đỉnhcó chỉ số lớn hơn, nghĩa là mỗi cung của nó thể biểu diễn dướidạng (v[i], v[j]) trong đó i < j.+ các v[i] là số hiệu cũ của đỉnh, i là số hiệu mới của đỉnh saukhi được đánh số+ Đồ thị ở hình bên các đỉnh đãđược đánh số thoả mãn điều kiện nêu trong định lý.- Để chứng minh định lý ta thuật toán đánh số cácđỉnh của đồ thị thỏa mãn điều kiện định lý như sau:Thuật toán: ta tìm tất cả các đỉnh không cung đi vào (gọi tắt làđỉnh trọc) lần lượt đánh số các đỉnh này theo thứ tự tuỳ ý, sauđó xoá các đỉnh trọc vừađánh số các cung đi ra từnó khỏi đồ thị, sau đó ta làm lại như trên đối với các đỉnh trọcmới cho đến khi tất cả các đỉnh được đánh số.Thuật toán được mô tả trong thủ tụctựa pascal sau: ProcedureNumbering;(* đầu vào:đồ thị hứng G=(V,E) với n đỉnh không chứa chu trình được cho bởidanh sáchkề ke(v), v thuộc V.đầu ra: là mảng chỉ số CS, sao cho mỗi cung đêù dạng(CS[u], CS[v] ) trong đóu < v.*)BEGINFor v thuộc V do Vao[v]:=0;(* tính bậc vào của đỉnhv *)For u thuộc V doFor v thuộc ke(u) do vao[v]:=vao[v]+1;Queue:= rỗng ; For v thuộc V do If vao[v] = 0 then queue <- v; Num := 0;While Queue ≠ rỗng do Beginu <- Queue; num:=num+1;CS[num]:=u;For v thuộc ke(u) doBeginVao[v]:=vao[v]-1;If vao[v]=0 then Queue <- v ;End; End;END;Chú ý: + Theo thuậttoán trên thì đỉnh được đánh số sau sẽ số hiệu lớn hơn đỉnhđược đánh số trước.+ Nếu nhưđồ thị chu trình thì áp dụngthuật toán đánh số trên thì nó sẽ không đánh số các đỉnh thuộcchu trình vì chúng không bao giờ trọc, lúc đó ta num < n. Vì vậy ta thể áp dụng thuật toán này để kiểm tra mộtđồ thị chu trình hay không.+ Độ phức tạpcủa thuật toán cỡ O(m). - Từ thuật toán trên ta thể xây dựng phát triển rấtnhiều ứng dụng:- Tìm đường đi ngắn nhất,dài nhất trên đồ thị trọngsố không chu trình.- Tìm đường đi dài nhất tính theo số cạnh không chu trình.2. Thuật toán tìm đường đi ngắnnhất, dài nhất Thuậttoán tìm đường đi ngắn nhất trên đồ thị hướng phi chu trìnhđược mô tả trong thủ tục sau:Procedurecritical_path;(* thủ tục tìmđường đi ngắn nhất từ đỉnhnguồn đến tất cả các đỉnh còn lại.đầu vào: đồ thị G=(V,E), trong đó V = { v[1], v[2], ,v[n].Với mỗi cung (v[i],v[j] ) thuộc V thì i < j.đồ thị đượccho bởi ma trận trọng số [ a[i,j] ] đầu ra: khoảng cách từv[1] đến cả các đỉnh còn lại được ghi trong mảngD[v[i]] , i = 2 , 3, ,n Truoc[v[i]] ghi nhận đỉnh đi trước v[i] trên đường đi từ v[1] đến v[i] *)BEGIN(* khởi tạo *)For j :=2 to n do d[v[j]] :=a[v[1],v[j]];D[v[1]] := 0;For i:=1 to n �1 doFor j :=i+1 to n do If (v[i],v[j] ) thuộcE then BeginIf d[v[j]]>d[v[i]]+ a[v[i],v[j]] thenBeginD[v[j]]:=d[v[i]] + a[v[i],v[j]]; Truoc[v[j]]:=v[i];End; End; END ;Ta thấy bản thuật toán trên là quyhoạch động với công thứcquy hoạch động làD[v[j]] = min( d[v[j]] , d[v[i]] + a[v[i],v[j]] ).Nhận xét: + trong thủ tục trên mỗicung của đồ thị phải xét quađúng một lần do đó độ phức tạp của thuật toán chỉ 0(m).+ thủ tục trênchỉ cho phép tìm đườn đi ngắn nhất, vậy để tìm được đường đi dài nhấtta phải đổidấu toàn bộ trọng số trên cung, hoặc đổi chiều bất đẳng thức trongthủ tục.3. Thuật toán tìm đường đi dài nhấttính theo số cạnh: - Thuật toántìm đường đi dài nhất tính theo số cạnh trên đồ thị không chu trìnhthực chất là được suy biến ra từ thuật toán đánh số tên làthuật toán đánh mức, tác giả Trần Đức Thiện đã bài viết vềthuật toán này do vậy ở bài viết này tôi chỉ nói tư tưởng thuậttoán:Thuật toán:Bước 1: khởi tạo k =1; Bước 2: đánh mức k cho các đỉnh trọc.Bước 3: k := k +1, lặp lại bước 2 cho đến khi cácđỉnh được đánh mức.- Để tìm đường đi : xuất phát từ đỉnh mức cao nhấtta lần ngước trở về theo quy tắc nếu đang ở mức k thì trở về đỉnhcó mức k-1.4. một số bài toán ứngdụng: Bài toán1: Bài toán thựchiện dự án: Một công trình gồm n côngđoạn đánh số từ 1 đến n, cómột số công đoạn mà việc thực hiện nó chỉ được tiến hành sau khimột số công đoạn nào đó đã hoàn thành. Thời gian hoàn thành côngđoạn i là t[i] với (i = 1 , 2, n). Giảsử thời điểm bắt đầu tiến hành thi công công trình là 0. Hãy tìmtiến độ thi công công trình (chỉrõ mỗi công đoạn phải được bắt đầu thực hiện vào thời điểm nào)để cho công trình được hoàn thành xong trong thời điểm sớm nhất thể được.- Dữ liệu vào file văn bản pert.inp: Dòng thứ nhất là số công đoạn n, n dòngtiếp theo dòng thứ i ghi các thông tin của công đoạn i : số thứ nhấtlà t[i], sau đó là các công việc trước công việc i.- Dữ liệu ra file văn bản pert. out: dòng đầu ghi thời điểm sớm nhất hoànthành toàn bộ công trình. dòng thứ i trong n dòng tiếp theo ghithời điểm bắt đầu thực hiện công việc i. Bài toán này ta thể giải trên mô hình đồ thị như sau: mỗi côngđoạn là một đỉnh, công đoạn i mà phải làm trước công đoạn j thìcó cung nối từ i tới j với trọngsố là t[i,j]. Gắn thêm 2 đỉnh giả 0 n+1 với ý nghĩa tương ứng với2 sự kiện là lễ khởi công (phải được thực hiện trước tất cả cáccông đoạn) lễ khánh thành (phải được thực hiện sau tất cả cáccông đoạn) coi t[0] = t[n+1] = 0. Ta gọi đồ thị thu được là G thì rõràng G là đồ thị hướng phi chu trình. Ta thấy thời điểm hoàn thànhsớm nhất công việc chính là thời điểm công đoạn cuối cùng đượcthực hiên xong. Vậy thực chất bài toán tìm thời điểm ngắn nhất hoànthành các công việc chính là bài toán tìm đường đi dài nhất từđỉnh 0 đến đỉnh n+1 trên đồ thị G, do đó ta thể áp dụng thuậttoán tìm đường đi dài nhấttrên đồ thị hướng phi chu trình nêu ở phần trên để giải bàitoán này. lẽ để cài đặt bài này thì không gì là khó do vậytôi để cho các bạn tự cài đặt cũng là giúp các bạn phần nào hiểurõ thêm về thuật toán.Bài toán 2: Mua vé tàu hoả: Tuyến đường sắt từ A đến B đi qua một số nhà ga. Tuyếnđường thể biểu diễn bởi một đoạn thẳng, các nhà ga là các điểmtrên nó, các nhà ga sẽ được đánh số từ 1 đến n bắt đầu từ nhàga A đến B (n là số lượng nhà ga). Giá vé đi giữa hai nhà ga phụthuộc vào khoảng cách giữa chúng, cụ thể cách tính giá vé đượccho bởi bảng sau: Trong đó 1≤L1 < L2 <L3 ≤109, 1 ≤C1 < C2 < C3≤ 109 Vé đi từ nhà ga này đến nhà ga khácchỉ thể đặt mua nếu khoảng cách giữa chúng không vượt quá L3. Nếukhoảng cách giữa hai nhà ga lớn hơn L3 thì ta phải mua một số vé. Yêu cầu: tìm cách đặt mua vé để đi lạigiữa hai nhà ga cho trước với chi phí mua vé là nhỏ nhất. Dữ liệu: vào từ file Rticket.inp: - Dòng đầu tiên ghi các sốnguyên L1, L2, L3, C1, C2, C3. - Dòng thứ 2 ghi số N (2 ≤ N ≤8000). - Dòng thứ 3 ghi hai số nguyên S, T làchỉ số của hai nhà ga mà ta cần tìm cách đặt mua vé với chi phí nhỏnhất. - Dòng thứ i trong số N-1 dòng tiếptheo ghi số nguyên là khoảng cách từ nhà ga A (ga 1) đến nhà ga i (i = 2 , 3 N) Kết quả: ghi ra file Rticket.out chi phí nhỏ nhất tìm được: Ví dụ:Xét bài toán: Việc đi lại(chi phí) từ S đến T tương đương với từ T đến S. Do vậy nếu sốhiệu S > T thì ta đổi chỗ S T.Ta quan niệm trênmô hình đồ thị như sau:mỗi nhà ga là một đỉnh của đồ thị, hai đỉnh i, j cung nối nếu khoảng cách giữa i j ≤L3, i <j. Trọng số trên cung là giá vé từ i đến j. Hướng của các cung làhướng từ A đến B. Rõ ràng đồ thị thu được là đồ thị hướngphi chu trình đã được đánh số, bài toán đưa về việc tìm đườngđi ngắn nhất trên đồ thị hướng phi chu trình. Vậy ta chỉ cần dùngthuật toán tìm đường đi ngắnnhất như: dijkstra, critical_path Tôi nghĩ các bạnnên làm bằng cả hai thuật toán trên để so sánh với nhau bạn sẽthấy critical_path trong trường hợp này là rất hiệu quả. Sau đây làtoàn văn chương trình:Progammvtauhoa; uses crt; const fi = ’Rticket.inp’; fo = ’Rticket.out’; MaxN = 8000 ; Maxk = maxlongint div 2; type mang1 = array [1 MaxN] of longint; var a,w: mang1; l1,l2,l3 : longint; c1,c2,c3 : longint; n,s,t : byte; f : text; procedure init; var i,tg: byte; begin assign(f, fi); reset(f); readln(f,l1,l2,l3,c1,c2,c3); readln(f,n); readln(f,s,t); a[1]:= 0; for i:=2 to n do readln(f,a[i]); close(f); if s > t then begin tg := s; s :=t; t := tg; end; end; function cp(u,v :byte):longint; var k:longint; begin k := a[v] - a[u]; if k <= l1 then cp := c1 else if k <= l2 thencp := c2 else if k <= l3then cp := c3 else cp :=Maxk; end; procedure critical_path; var i, j : byte; k : longint; begin for i:=s to t do w[i] := Maxk; w[s] := 0; for i:=s to t-1 do for j:=i+1 to t do begin k := cp(i, j); if w[j] > w[i] + k then w[j] := w[i] + k; if k = Maxk then break; end; end; procedure result; begin assign(f, fo); rewrite(f); writeln(f,w[t]); close(f); end; BEGIN critical_path; result; END. . Rõ ràng đồ thị thu được là đồ thị có hướngphi chu trình đã được đánh số, bài toán đưa về việc tìm đườngđi ngắn nhất trên đồ thị có hướng phi chu trình. . thuật toán hết sức hiệu quả trênđồ thị có hướng phi chu trình và những bài toán ứng dụng rất lýthú. Trước hết ta xét một thuật toánquan trọng sau: 1. Thuật

Ngày đăng: 11/09/2012, 14:59

Từ khóa liên quan

Tài liệu cùng người dùng

Tài liệu liên quan