1. Trang chủ
  2. » Công Nghệ Thông Tin

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

6 2,1K 44
Tài liệu đã được kiểm tra trùng lặp

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

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 6
Dung lượng 56,5 KB

Nội dung

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

Trang 1

Những thuật toán hiệu quả trên đồ thị có hướng phi chu trình

Ngô Quốc Hoàn

Đồ thị là một lĩnh vực quan trọng trongtoán học rời rạc và 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ị có 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ị 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 toán đánh số

Định lý: Giả sử G là đồ thị có hướngphi chu trình, khi đó các đỉnh của nó có thể đánh số

sao cho mỗicung của đồ thị chỉ hướng từ đỉnh có chỉ số nhỏ hơn đến đỉnhcó chỉ số lớn hơn, nghĩa là mỗi cung của nó có 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 có 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 có 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ố và 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ị có 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 đêù có dạng(CS[u], CS[v] ) trong đó

u < v.*)

BEGIN

For v thuộc V do Vao[v]:=0;

(* tính bậc vào của đỉnhv *)

For u thuộc V do

For v thuộc ke(u) do vao[v]:=vao[v]+1;

Queue:= rỗng ;

For v thuộc V do

Trang 2

If vao[v] = 0 then queue <- v;

Num := 0;

While Queue ≠ rỗng do

Begin

u <- Queue;

num:=num+1;

CS[num]:=u;

For v thuộc ke(u) do

Begin

Vao[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ẽ có số hiệu lớn hơn đỉnhđược đánh số trước

+ Nếu nhưđồ thị mà có 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 có num < n Vì vậy ta có thể áp dụng thuật toán này để kiểm tra mộtđồ thị có 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 có thể xây dựng và 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ị có trọngsố và không chu trình

- Tìm đường đi dài nhất tính theo số cạnh và 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ị có 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ảng

D[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 do

For j :=i+1 to n do

If (v[i],v[j] ) thuộcE then

Begin

If d[v[j]]>d[v[i]]+ a[v[i],v[j]] then

Begin

D[v[j]]:=d[v[i]] + a[v[i],v[j]];

Trang 3

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ỉ có 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ất

ta 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ố và có tên làthuật toán đánh mức, tác giả Trần Đức Thiện đã có 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 có 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 có 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 có 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 và 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) và lễ khánh thành (phải được thực hiện sau tất cả cáccông đoạn) và coi t[0] = t[n+1] = 0 Ta gọi đồ thị thu được là G thì rõràng G là đồ thị có 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 có thể áp dụng thuậttoán tìm đường đi dài nhấttrên đồ thị có hướng phi chu trình nêu ở phần trên để giải bàitoán này Có lẽ để cài đặt bài này thì không có 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

Trang 4

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 có 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ỉ có 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 và 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 có cung nối nếu khoảng cách giữa i và j

≤L3, và 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ị 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 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 và 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;

Trang 5

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

Trang 6

assign(f, fo); rewrite(f); writeln(f,w[t]);

close(f);

end;

BEGIN

critical_path;

result;

END

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

w