CẤU TRÚC ĐỒTHỊ Laptrinh_Hieu 19 I. Cấu trúc lưu trữ 1. 1. Ma trận kề 1 2 j N 2 i X N - A[i, j] = X: Có cung (i, j) - A[i, j] = 0: Không có cung (i, j). Nếu đồthị có trọng số thì X = trọng số. Nếu đồthị không có trọng số thì X = 1. Nếu đồ vị vô hướng thì A[i, j] ≠ A[j, i] 1. 2. Danh sách lân cận II. Các thuật toán cơ bản với cấu trúc ma trận 2. 1. Khai báo const MAX =100; Type mang =array[1 100,1 100] of byte; mang1 = array[1 100] of integer; mang2 = array[1 100] of boolean; var G,T: mang; {Do thi} n,top,d,c: integer; ctham : mang2; S,tr,kq: mang1; {Stack} {Đọc đồthị từ file} procedure load_file; var i,j: integer; f: text; begin assign(f,'DOTHI.dat'); {Kiểm tra sự tồn tại của file} {$I-} reset(f); close(f); {$I+} if IOResult <> 0 then begin writeln('File khong ton tai'); readln; halt; {Thoát khỏi ứng dụng} end; reset(f); readln(f,n); for i:=1 to n do begin for j:=1 to n do read(f,g[i,j]); readln(f); end; end; 2. 2. Duyệt sâu giải thuật đệ quy procedure sau(u: integer); {Thủ tục con lồng nhau} procedure try(i: integer); var j: integer; begin write(i,' '); ctham[i] := false; for j:=1 to n do if ctham[j]and (g[i,j]<>0) then begin try(j); end; end; begin fillchar(ctham,n,true); try(u); end; 2. 3. Duyệt rộng procedure rong(u:integer); var i,j: integer; begin fillchar(ctham,MAX, true); d := 1; c := 0; {Khởi tạo Queue rỗng} write(u,' '); ctham[u]:= false; {thăm nút đầu tiền} c := c+1; s[c] := u; {Nạp U vào Queue} while d<=c do begin i := s[d]; inc(d); {Lấy ra khỏi Queue} for j:=1 to n do if (g[i,j]<>0)and ctham[j] then begin ctham[j] := false; write(j,' '); inc(c); s[c] := j; {Nạp J vào Queue} end; end; end; 2 2 1 3 3 3 2 5 4 3 4 5 V[1] V[2] V[3] V[4] V[5] CẤU TRÚC ĐỒTHỊ Laptrinh_Hieu 20 2. 4. Tìm đường đi ngắn nhất với đồthị không có trọng số { Vận dụng duyệt rộng để giải} procedure ngannhat(u,v: integer); var i,j: integer; begin fillchar(ctham,MAX, true); d := 1; c := 0; tr[u] := u; ctham[u]:= false; c := c+1; s[c] := u; while d<=c do begin i := s[d]; inc(d); for j:=1 to n do if (g[i,j]<>0)and ctham[j] then begin tr[j] := i; {luu vet} ctham[j] := false; inc(c); s[c] := j; end; end; { Tìm đường theo vết} i := v; d := 1; kq[d] := v; while i <> u do begin d := d+1; kq[d] := tr[i]; i := tr[i]; end; write('duong di: '); for i:= d downto 1 do write(kq[i],' '); end; 2. 5. Kiểm tra liên thông procedure try1(i: integer); var j: integer; begin ctham[i] := false; for j:=1 to n do if ctham[j]and (g[i,j]<>0) then begin try1(j); end; end; function lienthong : boolean; var i:integer; begin fillchar(ctham, MAX, true); try1(1); for i:=1 to n do if ctham[i] = true then begin lienthong := false; exit; end; lienthong := true; end; 2. 6. Đếm số miền liên thông function somien: integer; var i, dem : integer; begin fillchar(ctham, MAX, true); dem := 0; for i:=1 to n do if ctham[i] = true then begin try1(i); dem := dem+1; end; somien := dem; end; 2. 7. Kiểm tra tồn tại chu trình function chutrinh : boolean; var a: mang; i: integer; procedure try(i: integer); var j: integer; begin tr[i] := tr[i] + 1; for j:=1 to n do if a[i,j] <> 0 then begin a[i,j] := 0; a[j,i] := 0; try(j); end; end; begin a := g; for i:=1 to n do tr[i] := 0; for i:=1 to n do if tr[i] = 0 then try(i); for i:=1 to n do if tr[i] > 1 then begin chutrinh := true; exit; end; chutrinh := false; end; CẤU TRÚC ĐỒTHỊ Laptrinh_Hieu 21 III. Cây khung và cây khung cực tiểu 3. 1. Dựng cây khung theo chiều sâu procedure try(i: integer); var j: integer; begin ctham[i] := false; for j:=1 to n do if ctham[j]and (g[i,j]<>0) then begin t[i,j] := g[i,j]; t[j,i] := g[j,i]; try(j); end; end; procedure khungsau; var i,j: integer; begin fillchar(ctham,MAX,true); for i:=1 to n do for j:=1 to n do t[i,j] := 0; try(1); hien(t); end; 3. 2. Dựng cây khung theo chiều rộng procedure khungrong; var i,j: integer; begin for i:=1 to n do for j:=1 to n do t[i,j] := 0; fillchar(ctham,MAX, true); d := 1; c := 0; ctham[1]:= false; c := c+1; s[c] := 1; while d<=c do begin i := s[d]; inc(d); for j:=1 to n do if (g[i,j]<>0)and ctham[j] then begin ctham[j] := false; t[i,j] := g[i,j]; t[j,i] := g[j,i]; inc(c); s[c] := j; end; end; hien(t); end; 3. 3. Thuật toán Kruskal {Cấu trúc lưu trữ khác của Đồ thị} Type canh = record u,v,ts: integer; end; dothi = array[1 200] of canh; var g: dothi; a: mang; n: integer; {so dinh} m: integer; {so canh} tr : mang1; nap : mang2; {Dựng đồthị G (mảng các cạnh) từ đồthị A} procedure dung_dothi(a: mang); var i,j: integer; begin m := 0; for i:= 1 to n do for j:= 1 to n do if a[i,j] <> 0 then begin inc(m); g[m].u := i; g[m].v := j; g[m].ts := a[i,j]; end; end; {Sắp xếp G tăng dần theo khoá TS} procedure sapxep; var tg: canh; i,j,c: integer; begin for i:=1 to m-1 do begin c := i; for j:= i+1 to m do if g[c].ts > g[j].ts then c := j; if c <> i then begin tg := g[c]; g[c] := g[i]; g[i] := tg; end; end; end; {Tìm gốc của cây chứa N} function goc(n: integer): integer; begin while tr[n] > 0 do begin n := tr[n]; end; goc := n; end; CẤU TRÚC ĐỒTHỊ Laptrinh_Hieu 22 {Thuật toán tìm cây khung cực tiểu} procedure kruskal; var i,u,v,dem: integer; begin for i:=1 to n do begin tr[i] := -1; nap[i] := false; end; sapxep; dem := 0; for i:=1 to m do begin u := goc(g[i].u); v := goc(g[i].v); if u <> v then {Không tạo chu trình} begin nap[i] := true; {nạp vào cây} tr[u] := v; {đưa vào 1 gốc} dem := dem + 1; if dem = n - 1 then break; end; end; writeln('CAY KHUNG CUC TIEU'); for i:=1 to m do if nap[i] then begin write(g[i].u,’ ’); write(g[i].v,’ ’); writeln(g[i].ts); end; end; IV. Các bài toán ứng dụng 4. 1. Bao đóng truyền ứng {Thuật toán để kiếm tra giũa 2 đỉnh I,J có tồn tại đường đi hay không?} procedure baodong; var i,j,k: integer; begin for i:= 1 to n do for j:= 1 to n do for k:= 1 to n do if (g[i,j] <> 0) or ((g[i,k]<>0)and (g[k,j]<>0)) then t[i,j] := 1; end; 4. 2. Một nguồn mọi đích {Tìm đỉnh u có d[u] nhỏ nhất và u chưa được thăm} function find_min: integer; var u,i,min: integer; begin min := 32000;{ vo cung } u := 0; for i:=1 to n do if (nap[i] = false) and (d[i] < min) then begin min := d[i]; u := i; end; find_min := u; end; {Bài toán một nguồn mọi đích} procedure dijstra(s: integer); var i,j,dem,tong: integer; begin {khởi tạo ma trận trọng số} for i:=1 to n do for j:=1 to n do if a[i,j] <> 0 then c[i,j] := a[i,j] else c[i,j] := 32000; {vocung} for i:=1 to n do begin d[i] := c[s,i]; nap[i] := false; tr[i] := s; end; d[s] := 0; repeat i := find_min; writeln('min = ',i); if (i = 0) then {không tìm thấy} break; {thoát lặp} nap[i] := true; {thăm} for j:=1 to n do {sửa lại d[j]} if (nap[j] = false) and (d[j] > d[i] + c[i,j]) then begin tr[j] := i; d[j] := d[i] + c[i,j]; end; until false; end; CẤU TRÚC ĐỒTHỊ Laptrinh_Hieu 23 {In đường đi ngắn nhất từ S T} procedure inkq(t: integer); var i,dem: integer; begin if d[t] = 32000 then writeln('khong co ddi toi ',t) else begin i := t; dem := 1; kq[1] := t; while i <> s do begin dem := dem +1; kq[dem] := tr[i]; i := tr[i]; end; writeln('Trong so = ',d[t]); for i:= dem downto 1 do write(kq[i],' -> '); writeln; end; end; 4. 3. Sắp xếp Tôpô {Đồ thị với cấu trúc lưu trữ móc nối} Type tronut = ^nut; type nut = record info: integer; next: tronut; end; dothi = array[1 100] of tronut; var V: dothi; g: mang; {Nạp cung (i,j) vào đồ thị} procedure nap(i,j: integer); var p: tronut; begin new(p); p^.info := j; p^.next := V[i]^.next; V[i]^.next := p; V[j]^.info := V[j]^.info + 1; end; {Tạo đồthị dạng danh sách lân cận từ ma trận kề } procedure tao_dothi; var i,j: integer; begin for i:=1 to n do {Khởi tạo đồthị rỗng} begin new(V[i]); V[i]^.info := 0; V[i]^.next := nil; end; for i:= 1 to n do for j:= 1 to n do if g[i,j] <> 0 then {tồn tại cung} begin nap(i,j); end; end; {Sắp xếp theo thứ tự tôpô} procedure topo; var p: tronut; i,m: integer; begin repeat {Tìm đỉnh không có cung đến} m := 0; for i:= 1 to n do if V[i]^.info = 0 then begin m := i; break; end; if m <> 0 then begin V[m]^.info:=-1;{đánh dấu thăm} write(m,' '); { Xoá các cung đi từ m} p := V[i]^.next; while p<> nil do begin dec(V[p^.info]^.info); p:= p^.next; end; end; until m = 0; end; 1 1 2 3 4 5 2 1 6 5 1 4 . 3. 3. Thuật toán Kruskal {Cấu trúc lưu trữ khác của Đồ thị} Type canh = record u,v,ts: integer; end; dothi = array[1 200] of canh; var g: dothi; a: mang;. các cạnh) từ đồ thị A} procedure dung_dothi(a: mang); var i,j: integer; begin m := 0; for i:= 1 to n do for j:= 1 to n do if a[i,j] <> 0 then begin