Thuật toán danh mục

10 463 6
Thuật toán danh mục

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

Thông tin tài liệu

Thuật toán danh mục

Thuật toán đánh mứcTrần Đức ThiệnTìm đường đi ngắn nhất trong đồ thị rất dễ (dùng thuật toán loang theo chiều rộng hoặc chiều sâu), song tìm đường đi dài nhất không phải là điều đơn giản. Xin giới thiệu với các bạn thuật toán đánh mức tìm đường đi dài nhất trong đồ thị có hướng không có chu trình.Thuật toán như sau:- Lặp : + Tăng k.+ Tìm các đỉnh không có cung đi ra gán cho nó mức k.+ Xoá tất cả các đỉnh vừa tìm được và các cung đi vào nó (các đỉnh vừa được đánh mức k).Đến khi tất cả các đỉnh được đánh mức.Khi đó độ dài lớn nhất có thể của đường đi là k. Chú ý rằng mức của một đỉnh chính là độ dài đường đi dài nhất xuất phát từ đỉnh đó.Sau khi đánh mức cho các đỉnh ta tìm đường đi dựa vào mảng mức và đồ thị đã cho:Đỉnh đầu tiên của đường đi là đỉnh u có mức k.Đỉnh tiếp theo là đỉnh v có mức k-1 và (u,v) có cung nối trực tiếp.Tiếp tục cho đến đỉnh có mức 1 chính là đường đi cần tìm.Tuy nhiên có thể dùng mảng sau[i] giữ lại đỉnh sau đỉnh i trong đường đi để lần đường đi được dễ dàng và nhanh chóng. Nhìn vào hình ta thấy nếu đỉnh u có mức k thì các đỉnh v có cung nối trực tiếp tới u sẽ có mức ≥ k+1 (bởi vì từ v có thể đi theo hướng khác không qua u cho đường đi dài hơn) và hoàn toàn có thể nằm trên đường đi nào đó chứa u, và là đỉnh trước trong đường đi. Ta dùng mảng sau nên gán ngược lại. Đó là mảng sau tạm thời, nếu có đường đi dài hơn nó sẽ tự động cập nhật lại ở bước gán mức sau. Nếu bạn không hiểu thì hoàn toàn có thể không dùng mảng sau, chỉ cần mảng mức là có thể tìm được đường đi, chỉ có điều sẽ mất rất nhiều thời gian cho việc đó.Một số điểm chú ý:+ Trong thuật toán thì ta phải xoá tất cả các đỉnh và các cung đi vào nó. Thực ra không phải làm công việc phức tạp đến vậy. Khi muc[u] > 0 thì tức là đỉnh u đã được đánh mức, ta không xét tới u nữa, coi như u đã bị xoá. Mặt khác thuật toán chỉ quan tâm đến số các cung đi ra, nên ta xoá cung bằng cách giảm số cung đi ra của đỉnh gốc tương ứng của cung.+ ở một bước nào đó trong vòng lặp đánh mức, nếu không tìm được đỉnh không có cung đi ra thì có nghĩa là đồ thị có chu trình (bạn hãy tự chứng minh điều này).+ Khi tìm đường đi thì không cần phải dùng tới mảng lưu trữ đường đi, vì ta tìm đường đi xuôi nên nếu không cần giữ lại đường đi dùng vào việc khác thì ta có thể in thẳng các đỉnh tìm được. Giả sử đồ thị có hướng n đỉnh được cho bởi ma trận quan hệ a[i,j] : a[i,j] = 1 nếu đỉnh i có cung nối trực tiếp đến đỉnhj, và a[i,j] = 0 nếu ngược lại. Chương trình sau cài đặt thuật toán trên:{ - Dữ liệu vào : Tệp Dothi.inp chứa n và ma trận a[i,j] (i,j = 1 n). }{ - Dữ liệu ra : Tệp Dothi.out chứa 1 đường đi dài nhất tìm được. }Program Tim_Duong_Di_Dai_Nhat_Trong_Do_Thi_Co_Huong_Phi_Chu_Trinh;Const inp = ′Dothi.inp′; out = ′Dothi.out′;maxn = 100; {$R+,Q+}type id = 1 maxn;var f : text;n,d,k : integer;sau,ra,muc : array[id] of byte; { ra[i] là số cung đi ra khỏi đỉnh i }a: array[id,id] of byte;Procedure nhap; var i,j : byte;beginassign(f,inp); reset(f);readln(f,n);for i := 1 to n do ra[i] := 0;for i := 1 to n dobeginfor j := 1 to n dobeginread(f,a[i,j]); if a[i,j] = 1 then inc(ra[i]);end;readln(f);end; close(f);end;procedure DanhMuc;var i,j : byte; found : boolean;begink := 0; d := 0; { d là số đỉnh đã được gán mức}for i := 1 to n do muc[i] := 0; { Khởi tạo tất cả các đỉnh đều chưa được gán mức }while d < n dobeginfound := false; k := k+1; { Biến found cho thêm để kiểm tra xem đồ thị có chu trình hay không }for i := 1 to n do if (ra[i] = 0) and (muc[i] = 0) then beginfound := true; d := d+1; muc[i] := k;end;if not found then begin writeln('Do thi co chu trinh');readln;halt; end;for i := 1 to n do if muc[i] = k thenfor j := 1 to n do if a[j,i] = 1 thenbegindec(ra[j]); sau[j] := i;end;end;end;procedure path; { Tìm đường đi }var i,v : byte;beginfor i := 1 to n do if muc[i] = k thenbeginv := i; break; { Tìm đỉnh đầu tiên của đường đi }end;assign(f,out); rewrite(f);writeln(f,k);for i := 1 to k dobeginwrite(f,v,' '); v := sau[v]; end; close(f);end;BEGINNhap; DanhMuc; Path;END.Độ phức tạp của thuật toán là O(n3), tuy nhiên trên thực tế áp dụng vào các bài toán cụ thể độ phức tạp của thuật toán được giảm xuống có thê chỉ còn O(n2).Sử dụng thuật toán đánh mức ta có thể giải bài toán sau:Cho ma trận m*n các số tự nhiên. Tìm đường đi dài nhất xuất phát từ một ô qua các ô của ma trận (Đường đi là một dãy các ô trong ma trận mà hai ô liền nhau trên đường đi có chung cạnh (chỉ có thể đi thẳng hoặc rẽ phải, trái) và để các số trên đường đi tạo thành một dãy tăng).Dễ thấy có thể áp dụng trực tiếp thuật toán đã nêu để giải bài toán này bằng cách coi mỗi ô là một đỉnh và hai đỉnh u,v có cung nối nếu ô tương ứng với đỉnh u có giá trị nhỏ hơn ô tương ứng với đỉnh v. Khi đó từ một đỉnh có thể đi trực tiếp đến nhiều nhất 4 đỉnh khác và do đường đi là dãy tăng nên không thể có chu trình, bài toán trở thành Tìm đường đi dài nhất trong đồ thị có hướng phi chu trình. Và chương trình có thể chạy tốt khi m, n ≤ 100.{Chương trình Bai2 OlympicSinhvien1999:}Program Tim_duong_di_dai_nhat_tao_day_tang_tren_ma_tran_Th;Constinp = ′matran.in2′;out = ′duongdi,ou2′;dx: array[1 4] of shortint= (-1,0,1,0); dy: array[1 4] of shortint= (0,1,0,-1);maxmn= 1--; {$R+,Q+}type id= 1 maxmn;var muc,ra,a: array[id,id] of integer; d,k,m,n: longint; i: text;proceduce nhap;var i,j: byte;beginassign(f,inp); reset(f);readln(f,m,n);for i:=1 to m dobeginfor j:= 1 to n doread(f,a[i,j]);readln(f);end; close;end;function tm(x,y: longint): boolean;begintm:= (x>0) and (y>0) and (x<=m) and (y<=n);end;proceduce khoitao;var i,j,k,x,y: longint;beginfor i:=1 to m do for j:=1 to n dobeginra[i,j]:= 0; muc[i,j]:=0; end;for i:=1 to m do for j:=1 to n dofor k:=1 to 4 do beginx:= i+dx[k]; y:= j+dy[k];if tm(x,y) thenif a[i,j] < a[x,y] theninc(ra[i,j]);end;end;proceduce danhmuc;var i,j,l,x,y: longint;begind:=0; k:= 0;while d < m*n dobegininc(k);for i:= 1 to m do for j:= 1 to n doif (ra[i,j]) and (muc[i,j] = 0) thenbegind:= d+1; muc[i,j]:=k;end;for i:= 1 to m do for j:= 1 to n do if muc[i,j]= k thenfor l:= 1 to 4 dobeginx:= i+dx[1]; y:= j+ dy[1];if tm(x,y) thenif a[x,y] < a[i,j] thendec(ra[x,y]);end;end;end;proceduce findpath;var i,j,x,y,xt,yt: longint;beginfor i:= 1 to m dofor j:= 1 to n do if muc[i,j]= k thenbeginx:= i; y:+ j; break;end;d:= 1;i:= x; j:= y;while muc[i,j] > 1 dobeginfor k:= 1 to 4 do beginxt:= i-dx[k]; yt:= j-dy[k];if tm(xt,yt) thenif muc[i,j]= muc[xt,yt] thenif a[i,j] < a[xt,yt] then begind:= d+1;i:= xt; j:= yt;break;end;end;end;assign(f,out); rewrite(f);writeln(f,d);writeln(f,x,″,y,″,a[x,y]);for i:= 1 to d-1 dofor k:= 1 to 4 dobeginxt:= x-dx[k]; yt:= y-dy[k];if tm(xt,yt) then if muc[x,y] = muc[xt,yt]+1 thenif a[x,y] <> begin x:= xt; y:= yt;writeln(f,x,″,y,″,a[x,y]);break;end;end;close(f);end;BEGINNhap; khoitao; danhmuc; findpath;END. . close(f);end;BEGINNhap; DanhMuc; Path;END.Độ phức tạp của thuật toán là O(n3), tuy nhiên trên thực tế áp dụng vào các bài toán cụ thể độ phức tạp của thuật toán được. giản. Xin giới thiệu với các bạn thuật toán đánh mức tìm đường đi dài nhất trong đồ thị có hướng không có chu trình .Thuật toán như sau:- Lặp : + Tăng k.+

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