Thuật toán Ford- Fulkerson - Tìm lượng cực đại trong mạng

Chương 1: MỘT SỐ KHÁI NIỆM CƠ BẢN CỦA LÝ THUYẾT ĐỒ THỊ I. MỘT SỐ KHÁI NIỆM CƠ BẢN CỦA LÝ THUYẾT ĐỒ THỊ II. MỘT SỐ THUẬT TOÁN TRÊN ĐỒ THỊ Chương 2: PHÁT BIỂU BÀI TOÁN LUỒNG TRÊN MẠNG I. PHÁT BIỂU BÀI TOÁN II. BÀI TOÁN LUỒNG CỰC ĐẠI VỚI KHẢ NĂNG THÔNG QUA CÁC CUNG – CÁC ĐỈNH CHƯƠNG III: PHÂN TÍCH VÀ CÀI ĐẶT I. PHÂN TÍCH BÀI TOÁN III. MỘT SỐ HÀM VÀ THỦ TỤC CỦA CHƯƠNG TRÌNH NGUỒN II. MỘT SỐ GIAO DIỆN CHÍNH CỦA CHƯƠNG TRÌNH

doc82 trang | Chia sẻ: lvcdongnoi | Lượt xem: 5820 | Lượt tải: 2download
Bạn đang xem trước 20 trang tài liệu Thuật toán Ford- Fulkerson - Tìm lượng cực đại trong mạng, để xem tài liệu hoàn chỉnh bạn click vào nút DOWNLOAD ở trên
u,v Î V; f[u,v]- luồng trên cung (u,v),(u,v Î V ) *) begin p[s]:=s; e[s]:= +¥; VT= V\{s}; PathFound:=true; While VT¹ Æ do Begin u<= VT; (* Lấy u từ VT *) for v Î V\VT do begin if (c[u,v]>0) and (f[u,v]< c[u,v]) then begin p[v]:= u; e[v]:= min { e[u],c[u,v] – f[u,v]}; VT = VT È {v}; (* Nạp v vào danh sách đỉnh có nhãn *) If v=t then exit; end; if (c[v,u]>0) and (f[v,u]>0) then begin p[v]:= -u; e[v]:= min {e[u],f[v,u]}; VT = VT È {v}; (* Nạp v vào danh sách đỉnh có nhãn *) If v=t then exit; end; end; PathFound:= false; end; procedure Inc_Flow; (* Tăng luồng theo đường tăng *) begin v:=p[t]; u:=t; tang:= e[t]; while u ¹s do begin if v>0 then f[v,u]:= f[v,u] + tang; else begin v:= -v; f[u,v]:= f[u,v] – tang; end; u:= v; v:= p[u]; end; end; Thuật toán Ford- Fulkerson được thực hiện nhờ thủ tục: Procedure Max_Flow; (* Thuật toán Ford- Fulkerson *) begin (* Khởi tạo: Bắt đầu từ luồng với giá trị 0 *) for u Î V do for v Î V do f[u,v]:=0; Stop:=false; While not Stop do begin Find_Path; If PathFound then Inc_Flow Else Stop:=true; end; end; Giả sử khả năng thông qua của tất cả các cung của đồ thị là các số nguyên. Khi đó sau mỗi lần tăng luồng, giá trị luồng sẽ tăng lên ít nhất là 1. Từ đó suy ra thuật toán Ford- Fulkerson sẽ dừng không quá val(f*) lần tăng luồng và cho ta luồng cực đại trong mạng. Đồng thời, rõ ràng f*(u,v) sẽ là số nguyên đối với mỗi cung (u,v)Î E. Từ đó ta có kết quả sau: Định lý 2 (Định lý về luồng cực đại trong mạng và lát cắt hẹp nhất). Luồng cực đại trong mạng bằng khả năng thông qua của lát cắt hẹp nhất. Định lý 3. (Định lý về tính nguyên). Nếu tất cả các khả năng thông qua là các số nguyên thì luôn tìm được luồng cực đại với luồng trên các cung là các số nguyên. Tuy nhiên, nếu các khả năng thông qua là các số rất lớn thì giá trị luồng cực đại cũng có thể là rất lớn và khi đó thuật toán mô tả ở trên sẽ đòi hỏi rất nhiều bước tăng luồng. Thí dụ trong hình 2 sẽ minh hoạ cho điều này. Hình 2(a) mô tả mạng cần xét với khả năng thông qua trên các cung. Hình 2(b) mô tả luồng trên các cung (số thứ hai bên cạnh cung ) sau khi thực hiện tăng luồng dọc theo đường tăng luồng (s,a,b,t). Hình 2(c) mô tả luồng trên các cung sau khi thực hiện tăng luồng dọc theo đường tăng luồng (s,b,a,t). Rõ ràng, sau 2.106 lần tăng luồng theo đường (s,b,a,t) và (s,b,a,t) một cách luân phiên ta thu được luồng cực đại. s t 106 106 106 106 1 b a (a) s t 106,0 106,1 106,1 106,0 1,1 b a (b) s t 106,1 106,1 106,1 106,1 1,0 b a (c) Hình 2. Ví dụ tồi tệ với thuật toán Ford- Fulkerson. Hơn thế nữa nếu các khả năng thông qua là các số vô tỷ, người ta còn xây dựng được ví dụ để cho thuật toán không dừng, và tệ hơn là dãy các giá trị luồng xây dựng theo thuật toán hội tụ thì nó còn không hội tụ đến giá trị luồng cực đại. Như vậy, muốn thuật toán làm việc hiệu quả, việc lựa chọn đường tăng luồng cần được tiến hành hết sức cẩn thận. Edmonds và Karp chỉ ra rằng nếu đường tăng luồng được chọn là đường ngắn nhất từ s đến t trên đồ thị Gf . Điều đó có thể thực hiện, nếu trong thủ tục tìm đường tăng Find_Path mô tả ở trên, danh sách VT được tổ chức dưới dạng QUEUE ( nghĩa là ta thực hiện tìm đường tăng bởi thủ tục tìm kiếm theo chiều rộng) thì thuật toán sẽ kết thúc sau không quá mn/2 lần sử dụng đường tăng luồng. Nếu để ý rằng, tìm kiếm theo chiều rộng trên đồ thị đòi hỏi thời gian O(n+m), thì thuật toán thu được sẽ có độ phức tạp tính toán là O(nm2). Nhờ cách tổ chức tìm đường tăng khéo léo hơn, người ta đã xây dựng được thuật toán với độ phức tạp tính toán tốt hơn như: O(n2m) (Dinic, 1970), O(n3) (Karzanov, 1974), O(n2m1/2) ( Cherkasky, 1977), O(nm log n) (Sleator- Tarjan,1980). II. BÀI TOÁN LUỒNG CỰC ĐẠI VỚI KHẢ NĂNG THÔNG QUA CÁC CUNG – CÁC ĐỈNH 1.Bài toán Giả xử trong đồ thị G = (V,E), ngoài khả năng thông qua của các cung c(u,v), ở mỗi đỉnh v Î V còn có khả năng thông qua của đỉnh là d(v), và đòi hỏi tổng luồng đi vào đỉnh v không còn vượt quá d(v), tức là Cần phải tìm luồng cực đại giữa s và t trong mạng như vậy. Xây dựng một mạng G’ sao cho: mỗi đỉnh v của G tương ứng với hai đỉnh v+, v- trong G’, mỗi cung (u,v) trong G ứng với cung (u,v+) trong G’, mỗi cung (v,w) trong G ứng với cung (v-,w+) trong G’. Ngoài ra, mỗi cung (v+,v-) trong G’ có khả năng thông qua là d(v), tức là bằng khả năng thông qua của đỉnh v trong G. 2. Giải quyết bài toán Từ mạng G = (V,E) khả năng thông qua các cung và các đỉnh. Ta sẽ giải quyết theo hai bước sau: 10 Xác định mạng G’. 20 Tìm luồng cực đại trong mạng G’. Bắt đầu từ luồng zero với khả năng thông qua cung. Thí dụ 1. C[u,v] C[v,t] C[s,v] C[u,t] C[s,u] t dt v dv u du s ds (a) C[v,t] C[u,t] C[s,v] C[s,u] t- dt t+ C[u,v] v- dv v+ u- du u+ s- ds s+ (b) Hình 1. Hình 1a cho ví dụ mạng G với khả năng thông qua ở cung và đỉnh. Hình 1b là mạng G’ tương ứng chỉ có khả năng thông qua ở các cung. Do luồng đi vào đỉnh v+ phải đi qua cung (v+,v-) với khả năng thông qua d(v), nên luồng cực đại trong G’ sẽ bằng luồng cực đại trong G với khả năng thông qua của các cung và đỉnh. Thí dụ 2. Xác định mạng G’ từ mạng G được cho như sau: s[7] 1 3 2 4 5 t[6] v[8] u[6] Hình 2. Mạng G với khả năng thông qua các cung và đỉnh t- 6 t+ 4 3 1 v- 8 v+ u- 6 u- 5 s- 7 2 s+ Hình 3. Mạng G’ tương ứng với khả năng thông qua các cung. 3. Một số bài toán tối ưu tổ hợp ứng dụng từ bài toán luồng Bài toán luồng cực đại có rất nhiều ứng dụng trong việc giải nhiều bài toán tổ hợp. Khó khăn chính ở đây là phải xây dựng tương ứng sao cho việc tìm luồng cực đại trong nó sẽ tương đương với việc giải bài toán đặt ra. Mục này sẽ giới thiệu một số bài toán như vậy. 3.1. Bài toán đám cưới vùng quê Có m chàng trai ở một làng quê nọ. Đối với mỗi chàng trai ta biết các cô gái mà anh ta vừa ý. Hỏi khi nào thì có thể tổ chức các đám cưới trong đó chàng trai nào cũng sánh duyên với cô gái mà mình vừa ý. Ta có thể xây dựng đồ thị với các đỉnh biểu thị các chàng trai và các cô gái, còn các cung biểu thị sự vừa ý của các chàng trai đối với các cô gái. Khi đó ta thu được một đồ thị hai phía. Thí dụ. Có 4 chàng trai {T1,T2,T3,T4} và 5 cô gái {G1,G2,G3,G4,G5}. Sự vừa ý cho trong bảng sau Chàng trai Các cô gái mà chàng trai ưng ý T1 G1, G4, G5 T2 G2 T3 G2, G3, G4 T4 G2, G4 Đồ thị tương ứng được cho trong hình 7. G1 s t G4 G3 G2 T4 T3 T2 T1 Hình 7. Mạng tương ứng với Bài toán đám cưới vùng quê Đưa vào điểm phát s và điểm thu t. Nối s với tất cả các đỉnh biểu thị các chàng trai, và nối t với tất cả các đỉnh biểu thị các cô gái. Tất cả các cung của đồ thị đều có khả năng tông qua bằng 1. Bắt đầu từ luồng 0, ta tìm luồng cực đại trong mạng xây dựng được theo thuật toán Ford- Fulkerson. Từ định lý về tính nguyên, luồng trên các cung là các số 0 hoặc 1. Rõ ràng là nếu luồng cực đại trong đồ thị có giá trị Vmax = m, thì bài toán có lời giải, và các cung với luồng bằng 1 sẽ chỉ ra cách tổ chức đám cưới thoả mãn điều kiện đặt ra. Ngược lại, nếu bài toán có lời giải thì Vmax=m. bài toán về các đám cưới vùng quê là một trường hợp riêng của bài toán về cặp ghép trên đồ thị hai phía mà để giải nó có thể xây dựng thuật toán hiệu quả hơn. 3.2. Bài toán về hệ thống đại diện chung Cho tập m phần tử X = {z1,z2,…,zm} Giả sử và là hai dãy tập con của X . Dãy gồm n phần tử khác nhau của X: được gọi là hệ thống các đại diện chung của hai dãy đã cho nếu như tìm được một hoán vị s của tập {1,2,…,n} sao cho là hệ thống các đại diện phân biệt của hai dãy và tức là điều kiện sau được thoả mãn: ai Î Ai Ç Bs(i), i =1,2,…,n. Xây dựng mạng G=(V,E) với tập đỉnh Trong đó đỉnh xi tương ứng với tập Ai đỉnh yi tương ứng với đỉnh Bi ,các phần tử ui,vi tưong ứng với phần tử zj . Tập các cung mạng của G được xác định như sau với với Khả năng thông qua của tất cả các cung được đặt bằng 1. Dễ dàng thấy rằng hệ thống đại diện chung của hai dãy và tồn tại khi và chỉ khi trong mạng G = (V,E) tìm được luồng với giá trị n. Để xét sự tồn tại của luồng như vậy có thể sử dụng thuật toán tìm luồng cực đại từ s đến t trong mạng G = (V,E). 3.3. Về một bài toán tối ưu rời rạc. Trong mục này ta sẽ trình bày thuật toán được xây dựng dựa trên thuật toán tìm luồng cực đại để giải một bài toán tối ưu rời rạc là mô hình toán học cho một số bài toán tối ưu tổ hợp. Xét bài toán tối ưu rời rạc (1) với điều kiện (2) xij = 0 hoặc 1, j=1,2,…,n (3) trong đó aij Î {0,1}, i= 1,2,…,m; j= 1,2,…,n, pi - nguyên dương, i=1,2,…,m. Bài toán (1)-(3) là mô hình toán học cho nhiều bài toán tối ưu tổ hợp thực tế. Dưới đây ta dẫn ra một vài ví dụ điển hình. 3.3.1 Bài toán phân nhóm sinh hoạt Có m sinh viên và n nhóm sinh hoạt chuyên đề. Với mỗi sinh viên i, biết aij =1, nếu sinh viên có i nguyện vọng tham gia vào nhóm j, aij =0, nếu ngược lại, và pi là số lượng nhóm chuyên đề mà họ có nguyện vọng tham gia và đảm bảo mỗi sinh viên i phải tham gia đúng pi nhóm, hãy tìm cách phân phối với số người trong nhóm có nhiều sinh viên tham gia nhất là nhỏ nhất có thể được. Đưa vào biến số xij =1, nếu sinh viên i tham gia vào nhóm j, xij =0, nếu ngược lại, i=1,2,…,m, j= 1,2,…,n, khi đó dễ thấy mô hình toán học cho bài toán đặt ra chính là bài toán (1)-(3):  Xét bài toán tối ưu rời rạc (1) với điều kiện (2) xij = 0 hoặc 1, j=1,2,…,n (3) trong đó aij Î {0,1}, i= 1,2,…,m; j= 1,2,…,n, pi - nguyên dương, i=1,2,…,m. 3.3.2 Bài toán lập lịch cho hội nghị Một hội nghị có m tiểu ban, mỗi tiểu ban cần sinh hoạt trong một ngày tại phòng họp phù hợp với nó. Có n phòng họp dành cho việc sinh hoạt của các tiểu ban. Biết aij =1, nếu phòng họp i là thích hợp với tiểu ban j, aij =0, nếu ngược lại, i=1,2,…,m; j=1,2,…,n. Hãy bố trí các phòng họp sao cho hội nghị kết thúc sau ít ngày làm việc nhất. Đưa vào biến số xij = 1, nếu bố trí tiểu ban i làm việc ở phòng j, xij =0, nếu ngược lại, i=1,2,…,m,j=1,2,…,n, khi đó dễ thấy mô hình toán học cho bài toán đặt ra chính là bài toán (1)-(3): Xét bài toán tối ưu rời rạc (1) với điều kiện (2) xij = 0 hoặc 1, j=1,2,…,n (3) trong đó aij Î {0,1}, i= 1,2,…,m; j= 1,2,…,n, pi - nguyên dương, i=1,2,…,m. Bổ đề 2. Bài toán (1)-(3) có phương án tối ưu khi và chỉ khi (4) Chứng minh. Điều kiện cần của bổ đề là hiển nhiên vì sự tồn tại phương án của bài toán suy ra các bất đẳng thức trong (4) được thực hiện ít nhất dưới dạng dấu đẳng thức. Để chứng minh điều kiện đủ, chỉ cần chỉ ra rằng nếu điều kiện (4) được thực hiện thì bài toán luôn có phương án. Thực vậy, giả sử điều kiện (4) được thực hiện. Khi đó nếu ký hiệu I+i = {1£ j £ n: aij = 1}, thì | I+i | ³ pi , i=1,2,…,m. Do đó nếu gọi Ii Ì I+i , | Ii | = pi , i=1,2,…,m, thì X* = (x*ij)mxn với các thành phần được xác đinh theo công thức x*ij =1, j Î Ii , x*ij =0, j Ï Ii , i=1,2,…,m, (5) Là phương án của bài toán (1)-(3). Bổ đề được chứng minh. Do (4) là điều kiện cần để bài toán (1)-(3) có phương án, nên trong phần tiếp theo ta sẽ luôn giả thiết rằng điều kiện này được thực hiện. Bây giờ ta sẽ chỉ ra rằng việc giải bài toán (1)-(3) có thể dẫn về việc giải một số hữu hạn bài toán luồng cực đại trong mạng. Trước hết, với mỗi số nguyên dương k, xây dựng mạng G(k) = (V,E) với tập đỉnh trong đó s là điểm phát, t là điểm thu, và tập cung mỗi cung e Î E được gán với khả năng thông qua q(e) theo qui tắc sau: q(s,ui) = pi , i = 1,2,…,m, q(ui,wj) = aij , i = 1,2,…,m; j = 1,2,…,n; q(wj,t) = k, j = 1,2,…,n. Hình 8 chỉ ra cách xây dựng mạng G(k). ui pi s t k wj q(ui,wj)=aij Hình 8. Mạng G(k). Ký hiệu: Bổ đề sau đây cho thấy mối liên hệ giữa luồng cực đại trong mạng G(k) và phương án của bài toán (1)-(3). Bổ đề 3. Giả xử đối với số nguyên dương k nào đó, luồng cực đại nguyên x* trong mạng G(k) có giá trị là s. Khi đó X* = (x*ij)mxn với các thành phần được xác định theo công thức. x*ij = x*(ui,wj), i=1,2,…,m; j=1,2,…,n. là phương án của bài toán (1)-(3). Chứng minh. Thực vậy, do luồng cực đại trong mạng có giá trị là s và luồng nguyên nên x*(s,ui) = pi, i= 1,2,…,m, x*(ui,wj) Î{0,1}, i= 1,2,…,m; j=1,2,…,n, từ đó suy ra Vậy X* là phương án của bài toán (1)-(3). Bổ đề được chứng minh. Bổ đề 4. Giả sử X*(x*ij) là phương án tối ưu của k* và là giá trị tối ưu của bài toán (1)-(3) khi đó luồng cực đại trong mạng G(k*) có giá trị s . Chứng minh. Do giá trị của luồng cực đại trong mạng G(k*) không vượt quá s nên để chứng minh bổ đề ta chỉ cần chỉ ra luồng giá trị s trong mạng G(k*).Xây dựng luồng theo công thức sau Dễ dàng kiểm tra được rằng là luồng trong mạng G(m) có giá trị là s . Bổ đề được chứng minh. Bổ đề 5 . Nếu k=m thì luồng cực đại trong mạng G(m) có giá tị là s Chứng minh. Lập luận tương tự như trong bổ đề 4, ta chỉ cần chỉ ra luồng với giá trị s trong mạng G(m) . Thực vậy,giả sử X*=(x*ịj)mxn là phương án của bài toán (1)-(3) xây dựng theo công thức 5. Xây dựng luồng theo công thức giống như trong chứng minh bổ đề 4, ta có luồng với giá trị s . Bổ đề được chứng minh. Từ bổ đề 3 và 4 suy ra việc giải bài toán (1)-(3) dẫn về việc tìm giá trị k* nguyên dương nhỏ nhất sao cho luồng cực đại trong mạng G(k*) có giá trị s.Bổ đề 5 cho thấy giá trị k*Î[1,m]. Vì vậy để giải bài toán (1)-(3) ta có thể áp dụng phương pháp tìm kiếm nhị phân trên đoạn [1,m] để tìm giá trị k*, trong đó ở mỗi bước cần giải một bài toán luồng cực đại. Để giải bài toán tìm luồng cực đại trong mạng, có thể sử dụng thuật toán đa thức như đã nói ở trên. Từ đó suy ra kết quả sau Định lý 5. Bài toán (1)-(3) giải được nhờ thuật toán đa thức với độ phức tạp tính toán của bài toán là log2m . ONF trong đó ONF là độ phức tạp tính toán của bài toán tìm luồng cực đại trong mạng G(k) Thí dụ 3. Bài toán phân nhóm sinh hoạt Giả sử có m sinh viên SV1, SV2,.., SVm và n nhóm sinh hoạt N1, N2,.., Nn. Gọi là ma trận đăng ký sinh hoạt theo nguyện vọng của sinh viên. với aij = 1 nếu SVi đăng ký nhóm Nj , aij = 0 nếu ngược lại Gọi là ma trận chứa số lượng từng chuyên đề mà SVi phải tham gia đúng Pi , i = 1..m chuyên đề. Bài toán đặt ra là xác định ma trận Với bij = 1 nếu SVi đăng ký Nj , bij = 0 nếu ngược lại. Sao cho: Và - Rõ ràng, ma trận A với tổng các phần tử trên hàng i là khả năng thông qua của đỉnh i. - Khả năng thông qua cung (i,j) là 1 nghĩa là SVi có đăng ký nguyện vọng sinh hoạt nhóm Nj. Giá trị luồng của cung này có thể là 1 hoặc 0 (SVi không được sinh hoạt nhóm Nj). - Điều kiện tối ưu của bài toán là tìm cách phân phối số người trong nhóm có nhiều SV tham gia nhỏ nhất chính là khả năng thông qua các cung vào đỉnh t. - Để giải quyết bài này, ta áp dụng Bổ đề 3 bằng cách cho khả năng thông qua các cung này bằng k và tìm luồng cực đại của mạng này. Đầu tiên, xét k = 1,2,...,m. Và áp dụng Bổ đề 4 để xác định k* với luồng cực đại tương ứng. Thí dụ 4 Xét bài toán với m = 3(SV) và n = 4 nhóm sinh hoạt Ma trận đăng ký sinh hoạt Ma trận chỉ tiêu đăng ký chuyên đề Khi đó ma trận kết quả phân nhóm tối ưu Hình sau là mạng với luồng cực đại biểu diễn phân nhóm sinh hoạt. Trong đó khả năng thông qua của các đỉnh SVi chính là khả năng thông qua của các cung (S,SVi) và bằng : Khả năng thông qua của các cung (Ni,t) là Khả năng thông qua của các cung (SVi,Nj) là 1, (i = 1..n, j = 1..m) 0 2 1 2 1 1 1 1 1 1 1 3 2 2 t N4 N3 N2 N1 S SV3 SV2 SV1 2 Hình 1. Mạng với luồng cực đại biểu diễn phân công sinh hoạt chuyên đề CHƯƠNG III PHÂN TÍCH VÀ CÀI ĐẶT I. PHÂN TÍCH BÀI TOÁN 1. Mô hình bài toán Giả xử trong đồ thị G, ngoài khả năng thông qua của các cung c(u,v), ở mỗi đỉnh v Î V còn có khả năng thông qua của đỉnh là d(v), và đòi hỏi tổng luồng đi vào đỉnh v không còn vượt quá d(v), tức là Cần phải tìm luồng cực đại giữa s và t trong mạng như vậy. Xây dựng một mạng G’ sao cho: mỗi đỉnh v của G tương ứng với hai đỉnh v+, v- trong G’, mỗi cung (u,v) trong G ứng với cung (u,v+) trong G’, mỗi cung (v,w) trong G ứng với cung (v-,w+) trong G’. Ngoài ra, mỗi cung (v+,v-) trong G’ có khả năng thông qua là d(v), tức là bằng khả năng thông qua của đỉnh v trong G. 2. Phương pháp giải quyết Từ mạng G = (V,E) với khả năng thông qua các cung các đỉnh. Ta tìm luồng cực đại của mạng qua hai bước sau: Bước 1: Xác định mạng G’. Bước 2: Tìm luồng cực đại trong mạng G’. Bắt đầu từ luồng zero với khả năng thông qua cung. Hai bước trên ta có thể biểu diễn dưới dạng sơ đồ thuật toán sau: Begin Mạng G Mạng G’ Luồng cực đại trên G’ End 3. Biểu diễn đồ thị 3.1 Biểu diễn mạng G với khả năng thông qua các cung - đỉnh Giả sử mạng G = (V,E), |V| = n. Ta có thể biểu diễn bởi ma trận trọng số A cấp n x n như sau: di nếu i = j c[i,j] nếu [i,j] Î E 0 nếu [i,j] Ï E A = ( aij ) = Trong đó: di là khả năng thông qua đỉnh i; C[i,j] khả năng thông qua cung [i,j]. 3.2 Biểu diễn mạng G’ tương ứng với mạng G Mạng tương ứng với G = (V,E), |V | = n là mạng G’ = (V’,E’), |V’| = 2 |V |, |E’| = 2 |E | - 1. Được biểu diễn thông qua ma trận A’ cấp (2n x 2n) như sau: A’ = ( a’ij ) = nếu i = j c[i,j] nếu [i,j] Î E’ Thí dụ 3. Như thí dụ trên có mạng G như sau: s[7] 1 3 2 4 5 t[6] v[8] u[6] Ta có ma trận biểu diễn mạng G : A = s u v t 7 5 2 0 s 0 6 1 4 u 0 0 8 3 v 0 0 0 6 t Tương tự từ mạng G’: t- 6 t+ 4 3 1 v- 8 v+ u- 6 u- 5 s- 7 2 s+ Ta có ma trận biểu diễn mạng G’ như sau: A’ = s+ s- u+ u- v+ v- t+ t- 0 7 0 0 0 0 0 0 s+ 0 0 5 0 2 0 0 0 s- 0 0 0 6 0 0 0 0 u+ 0 0 0 0 1 0 4 0 u- 0 0 0 0 0 8 0 0 v+ 0 0 0 0 0 0 3 0 v- 0 0 0 0 0 0 0 6 t+ 0 0 0 0 0 0 0 0 t- Áp dụng T.T Ford-Fulkerson tìm luồng cực đại cho mạng G’ ta được mạng cực đại và ma trận biểu diễn nó như sau: C = s+ s- u+ u- v+ v- t+ t- 0 6 0 0 0 0 0 0 s+ 0 0 4 0 2 0 0 0 s- 0 0 0 4 0 0 0 0 u+ 0 0 0 0 0 0 4 0 u- 0 0 0 0 0 2 0 0 v+ 0 0 0 0 0 0 2 0 v- 0 0 0 0 0 0 0 6 t+ 0 0 0 0 0 0 0 0 t- Với Val(f*) = 6 III. MỘT SỐ HÀM VÀ THỦ TỤC CỦA CHƯƠNG TRÌNH NGUỒN procedure Initgr; var Gd, Gm: Integer; Radius: Integer; begin Gd := Detect; InitGraph(Gd, Gm, 'D:\bp\bgi '); if GraphResult grOk then Halt(1); end; (*==================================================*) procedure readfile; var i,j:word; kt:array[1..max] of integer; begin readln(ff,Ssv,Sn); for i:=1 to Ssv do begin for j:=1 to Sn do read(ff,C^[i,j]); readln(ff,e[i]); end; end; (*==============================================*) {procedure sum_ei; var kt:array[1..max] of integer; snc,i,j:word; begin snc:=snc+1; for i:=1 to Ssv do kt[i]:=kt[i]+C^[i,j]; end; function Ok:boolean; var ktra:boolean; kt:array[1..max] of integer; r,i,j:word; begin readfile; sum_ei; ktra:=false; for i:=1 to ssv do begin r:=0; for j:=1 to sn do r:= r+C^[i,j]; if r < kt[i] then begin ktra:=false; exit; end else ktra:=true; end; Ok:=ktra; end;} (*==============================================*) function min(a,b:integer):integer; begin if a>b then min:=b else min:=a; end; (*==========================================*) function EmptyVt:word; var i:word; begin EmptyVt:=0; for i:=1 to N do if Vt[i]=1 then begin EmptyVt:=i; exit; end; end; (*================================================*) {Tìm đường đi để tăng luồng} procedure find_path; begin fillchar(Vt,sizeof(vt),0); ee[sw]:=INF; p[sw]:=sw; Vt[sw]:=1; pathfound:=true; while EmptyVt0 do begin u:=EmptyVt; Vt[u]:=2; for v:=1 to n do if (Vt[v]=0) and(uv) then begin if (C^[u,v]>0) and (f^[u,v]<C^[u,v]) then begin p[v]:=u; ee[v]:=min(ee[u],C^[u,v]-f^[u,v]); Vt[v]:=1; if v=t then exit; end; if (C^[v,u]>0) and (f^[v,u]>0) then begin p[v]:=-u; ee[v]:=min(ee[u],f^[v,u]); Vt[v]:=1; if v=t then exit; end; end; end; pathfound:=false; end; (*=========================================*) {tìm được đường đi rồi đến thủ tục tăng luồng} procedure inc_flow; begin v:=p[t];u:=t; while usw do begin if v>0 then begin f^[v,u]:=f^[v,u]+ee[t];end else begin v:=-v; f^[u,v]:=f^[u,v]-ee[t]; end; u:=v;v:=p[u]; end; end; (*==========================================*) {thuật toán tăng luồng toàn bộ để tìm luồng cực đại} procedure Max_flow; var stop:boolean; begin for u:=1 to N do for v:=1 to N do f^[u,v]:=0; stop:=false; while not stop do begin Find_path; if pathfound then inc_flow else stop:=true; end; end; (*======================================================*) {Chuyển Ma trận cho dưới dạng quan hệ thành ma trận để thực hiện luồng cực đại input : C[i,j] là quan hệ hàng i và cột j c[i,j]=1 else c[i,j]:=0; Sn:so cột Ssv:so hàng e[i]:so bat buoc cua hàng i } procedure TransMatrixFlow; var i,j:word; begin N:=Sn+Ssv+2; sw:=1; t:=N; for i:=1 to Ssv do for j:=1 to Sn do F^[i,j]:=c^[i,j]; fillchar(c^,sizeof(c^),0); {gan them diem cuoi den tat ca cac nhom co luong vo cung} for j:=1 to Ssv do C^[1,j+1]:=e[j]; for j:=1 to Sn do for i:=1 to Ssv do C^[i+1,Ssv+j+1]:=F^[i,j]; {gan them diem dau den tat ca cac SV co luong vo cung} for i:=1 to Sn do begin C^[Ssv+i+1,N]:=INF; end; end; (*===================================================*) {đổi 2 nhóm sao cho chênh lệch là bé nhất} procedure changegroup(n1,n2:word); var c1,i,j,k1,k2:word; begin if F^[Ssv+1,n1]=F^[Ssv+1,n2] then exit; if F^[Ssv+1,n1]>F^[Ssv+1,n2] then begin k1:=n1;k2:=n2;end else begin k1:=n2; k2:=n1; end; for c1:=1 to Ssv do if (F^[Ssv+1,k1]>F^[Ssv+1,k2]) and (c1<=Ssv) and (F^[c1,k1]=1)and (C^[c1,k2]=1) and (F^[c1,k2]=0) then begin F^[c1,k1]:=0;F^[c1,k2]:=1; dec(F^[Ssv+1,k1]); inc(F^[Ssv+1,k2]); inc(c1); end; end; (*==============================================*) procedure TransresultM; var t,i,j:word; begin for i:=1 to Ssv do begin for j:=1 to Sn do begin F^[i,j]:=F^[i+1,Ssv+j+1]; C^[i,j]:=C^[i+1,Ssv+j+1]; end; F^[i,Sn+1]:=e[i]; end; {tinh so SV trong nhom} for j:=1 to Sn do begin t:=0; for i:=1 to Ssv do t:=t+F^[i,j]; F^[Ssv+1,j]:=t; end; for i:=1 to Sn do for j:=1 to Sn do if ij then changeGroup(i,j); end; (*================================================*) procedure init; begin clrscr; new(C); if c=nil then writeln('Khong du bo nho'); new(F); if F=nil then writeln('Khong du bo nho'); end; (*===============================================*) procedure finish; begin if cnil then dispose(C); if Fnil then dispose(F); end; procedure writexy(x,y:integer;clr:byte;s:string); begin gotoxy(x,y); textattr:=clr; write(s); end; (*===================================================*) (* copy ký tự ch, tại vị trí thứ j ,trong chuỗi s*) function cpystr(s:string;ch:char;j:byte):string; var ie,i,is:byte; nn,nl:byte; begin nn:=0; cpystr:=''; nl:=length(s); i:=1; while (ij) do begin if s[i]=ch then nn:=nn+1; inc(i); end; if i<nl then begin is:=i; while (ich) do inc(i); if i<=nl then begin ie:=i; cpystr:=copy(s,is,ie-is); exit; end; end; end; (*========================================================*) function popupmenu(x,y,w,nitem:integer;pmenu:string;clrsel,clback:byte):byte; var cmd,index,i:byte; ssel:string; c:char; begin ssel:=''; index:=1; for i:=1 to w do ssel:=ssel+' '; drawwindow(x,y,x+w+2,y+nitem+1,$70,$70,1); {dat mau cho khung hoi thoai} for i:=1 to nitem do writexy(1,i,clback,cpystr(pmenu,'/',i)); repeat writexy(1,index,clrsel,ssel); writexy(1,index,clrsel,cpystr(pmenu,'/',index)); c:=readkey; writexy(1,index,clback,ssel); writexy(1,index,clback,cpystr(pmenu,'/',index)); case c of #72:if index>1 then dec(index) else index:=nitem; #80:if index<nitem then inc(index) else index:=1; #75:cmd:=$80; #77:cmd:=$81; #13:cmd:=index; #27:cmd:=0; end; until (c=#13)or (c=#27) or (cmd>=$80); popupmenu:=cmd; end; (*=============================================*) function menubar(clr,clrsel,opt:byte):word; var index,i :byte; cmd :word; xs :array[1..NUMPOPUP] of byte; luuscreen:^byte; begin xs[1]:=2; index:=1; getmem(luuscreen,80*25*2); if luuscreen=nil then exit; for i:=2 to NUMPOPUP do xs[i]:=xs[i-1]+length(cpystr(MenuBarStr,'/',i))+2; window(1,1,80,1); textattr:=clr; {const MenuBarStr:string='/File / Exe / Help /';} clrscr; for i:=1 to NUMPOPUP do writexy(xs[i],1,clr,cpystr(MenuBarStr,'/',i)); if opt=0 then exit; move(ptr($B800,0)^,luuscreen^,80*25*2); repeat window(1,1,80,1); textattr:=clr; writexy(xs[index],1,clrsel,cpystr(MenuBarStr,'/',index)); cmd:=popupmenu(xs[index],2,20,popupnum[index],mnupopup[index],clrsel,clr); if (cmd=$80) or (cmd=$81) then Move(luuscreen^,ptr($B800,0)^,80*25*2); { function Ptr(Seg, Ofs: Word): Pointer; Converts a segment base and an offset address to a pointer-type value.} {procedure Move(var Source, Dest; Count: Word);Copies bytes from source to dest.} if (cmd=$80) then if (index>1) then dec(index) else index:=NUMPOPUP; if (cmd=$81) then if (index<NUMPOPUP) then inc(index) else index:=1; until (cmd=0) or (cmd<$80); (*cau lenh thay doi gia tri cua cac tuy chon kkkkkkkkkkkkkkkkkk*) if (cmd0) then cmd:=(index shl 8) or cmd; move(ptr($B800,0)^,luuscreen^,80*25*2); freemem(luuscreen,80*25*2); menubar:=cmd; end; (*=================================================*) procedure writestatus(s:string); begin textattr:=$74; clrscr; write(s); end; (*=================================================*) procedure message(s:string); begin drawwindow(20,5,60,7,$21,$21,2); write(s); readln; end; (*==================================================*) function inputbox(tilte:string):string; var s:string; begin drawwindow(20,10,60,13,$21,$21,2); write(tilte); drawwindow(25,12,55,12,$7F,$1F,0); readln(s); inputbox:=s; end; (*=============================================*) procedure repaint; begin { window(1,1,80,25);} clrscr; textattr:=$00; window(1,25,80,25); writestatus(' F10'); writexy( 3,23,$70,' Show Menu'); {(*$70:dat mau cho statusbar*)} menubar($70,$70,0); {dat mau cho toolbar} drawwindow(1,2,80,24,$1f,$1F,0); {(*$1f,$1f mau nen:3bit cao, mau chu :4 bit thap*)} end; (*=========================================================*) (* CAC THU TUC TUONG UNG VOI CAC MENU *) (*=========================================================*) function FileExit(filename:ss):boolean; var f:text; begin {$I-} assign(f,filename); reset(f); close(f); {$I+} FileExit:=(Ioresult=0)and(filename''); end; {-------------------------------------------------------------------------------------} procedure savefile; var i,j:word; begin repaint; fileinput:=inputbox('Nhap Duong dan va ten File:'); assign(ff,fileinput); {$I-} rewrite(ff); {$I+} if IOresult0 then message('File khong hop le hoac sai duong dan') else begin for i:=1 to ssv+1 do begin for j:=1 to sn do write(ff,F^[i,j]:5); writeln(ff,e[i]:5); end; close(ff); end; end; (* ============================================= *) procedure openfile; var i,j:byte; begin repaint; fileinput:=inputbox('Nhap Duong dan va ten File :'); assign(ff,fileinput); {$I-} reset(ff); {$I+} if IOresult0 then message('File khong ton tai hoac sai duong dan') else begin readfile; close(ff); end; repaint; drawwindow(1,2,79,24,$1F,$1F,2); writeln('Ma tran dang ky :'); writeln; for i:=1 to Ssv do begin for j:=1 to Sn do write(C^[i,j]:3);writeln; end; writeln; for i:=1 to Ssv do begin gotoxy(25,i+2); writeln(e[i]); end; gotoxy(22,1);write('Chi tieu :'); readln; end; (*-----------------------------------------------------------------------------------*) procedure newfile; var f:string; j,i,cn,m:word; key:char; begin REPAINT; drawwindow(1,2,79,24,$1F,$1F,2); write('Nhap So hang <= 200 : ');readln(ssv); write('Nhap So cot <= 100 : ');readln(sn); writeln('CHU Y !'); writeln('1. Hang i quan he cot j thi C[i,j] = 1, nguoc lai C[i,j]= 0.'); writeln('2. Nhap Du Lieu chi gom cac so 0 hoac 1.'); writeln('3. Neu ban nhap sai ban phai nhap lai .'); writeln('4. Cho den khi thoa man dieu kien de bai.'); for i:=1 to ssv do begin for j:=1 to sn do begin repeat write('C[',i,',',j,']:='); readln(C^[i,j]); until C^[i,j] in [0,1]; end; repeat write('Nhap so nhom ma hang ',i,' Phai tham gia: P',i,' = '); readln(e[i]); if e[i] > sn then begin writeln('Nhap sai !, Nhap lai .'); writeln('So nhom phai tham gia P',i,' <= ',sn,' (So ban vua nhap)'); end; until e[i] <= sn; end; repaint; f:=inputbox('Nhap Duong dan va ten File:'); assign(ff,f); {$I-} rewrite(ff); {$I+} if IOresult0 then message('File khong hop le hoac sai duong dan') else begin writeln(ff,ssv,' ',sn); for i:=1 to ssv do begin for j:=1 to sn do write(ff,C^[i,j],' '); writeln(ff,e[i]); end; close(ff); end; end; (******************************************************************) (* CHUAN BI MO PHONG *) (******************************************************************) procedure xuat; begin setcolor(9); settextstyle(1,0,1); settextjustify(2,8); outtextxy(460,405,' GVHD : DO NHU AN '); outtextxy(438,428,' SVTH : Ngo Tao Vinh ' ); outtextxy(438,446,' LOP : Tin 40 DHTS '); end; (*----------------------------------------------------------------------*) procedure display; begin setfillstyle(1,7); bar(1,0,getmaxx,24); setfillstyle(1,8);(* mau nen*) bar(1,25,getmaxx,getmaxy-100); setcolor(9); Bar(1,25,getmaxx,getmaxy); setcolor(2); (*set color chu *) bar(1,getmaxy-90,getmaxx,getmaxy); setcolor(2); settextstyle(1,0,2); settextjustify(1,1); outtextxy(160,450,'Phan Nhom Sinh hoat '); outtextxy(170,420,'Ford - Fulkerson Algorithms'); xuat; setcolor(15); line(1,getmaxy-92,getmaxx,getmaxy-92); line(1,getmaxy-91,getmaxx,getmaxy-91); line(321,25,321,getmaxy-92); line(321,26,321,getmaxy-93); line(1,22,getmaxx,22); line(1,23,getmaxx,23); end; (*------------------------------------------------------------------------*) procedure vechu(x,y:integer;st:string;mau,co,cl,jus:word); begin setcolor(cl); settextjustify(jus,1); settextstyle(mau,0,co); outtextxy(x,y,st); end; {-----------------------------------------------------------------------} {thu tuc ve khung voi ca c toa do (x1,y1) x2,y2 voi mau cl} procedure khung(x1,y1,x2,y2,cl:integer); begin setcolor(cl); line(x1,y1,x2,y1); line(x1,y1,x1,y2); line(x1,y2,x2,y2); line(x2,y1,x2,y2); end; (*=====================================================*) procedure vechu1; var i,j:byte; begin settextstyle(0,1,0); setcolor(15); outtextxy(15,140,'Sinh Vien Dang Ky'); setcolor(14); line(21,80,21,215); line(16,210,21,215); line(26,210,21,215); setcolor(15); settextstyle(0,0,0); outtextxy(80,80,'Nhom Dang Ky'); setcolor(14); line(40,90,190,90); line(185,85,190,90); line(185,95,190,90); for j:=1 to sn do begin for i:=1 to ssv do begin str(C^[i,j],s); setcolor(15); settextstyle(0,0,1); outtextxy(21*j+7,14*i+85,s); end; end; {j:=sn+1;} for i:=1 to ssv do begin str(e[i],s); setcolor(15); settextstyle(0,0,1); outtextxy(210,14*i+85,s); setcolor(15); settextstyle(0,0,0); outtextxy(190,80,'Chi Tieu'); end; (* Viet ma tran ket qua *) { setcolor(15); settextstyle(0,1,0); outtextxy(getmaxx div 2+15,80,'Sinh Vien Duoc PN'); setcolor(14); line(getmaxx div 2+25,90,30,21,((getmaxY-44) div 2)+165);} { line(getmaxx div 2+21,((getmaxY-44) div 2)+30,21,((getmaxY-44) div 2)+165); line(getmaxx div 2+16,((getmaxY-44) div 2)+160,21,((getmaxY-44) div 2)+165); line(getmaxx div 2+26,((getmaxY-44) div 2)+160,21,((getmaxY-44) div 2)+165); setcolor(15); settextstyle(0,0,0); outtextxy(40,((getmaxY-44) div 2)+30,'Nhom Dang Ky'); setcolor(14); line(40,((getmaxY-44) div 2)+40,190,((getmaxY-44) div 2)+40); line(185,((getmaxY-44) div 2)+35,190,((getmaxY-44) div 2)+40); line(185,((getmaxY-44) div 2)+45,190,((getmaxY-44) div 2)+40);} for j:=1 to sn do begin for i:=1 to ssv do begin str(F^[i,j],s); setcolor(15); {outtextxy(21*j+7,14*i+(getmaxY-44) div 2+40,s);} outtextxy(getmaxx div 2+25+21*j+7,14*i+85,s); end; end; {setcolor(15); outtextxy(100,70,'Ma Tran Dang Ky'); outtextxy(100,240,'Ma Tran Ket Qua');} { for i:=1 to ssv do begin for j:=1 to sn do begin str(C^[j,i],s); setcolor(15); outtextxy(20*i+ssv,20*j+(sn+1)+70,s); end; end;} end; (*------------------------------------------------------------------------*) procedure toado1; var i,j,k:integer; x11,y11,x22,y22:integer; tdotrai,tdophai,qqq,tdoy,temp,sogia:word; begin setcolor(15); tdotrai:=15;tdophai:=getmaxx div 2-15; tdoy:=getmaxy div 2; i:=1;k:=1;qqq:=1; while (qqq<=ssv+sn) do begin if temp<6 then sogia:=100 else sogia:=50; toado[i].x:=30+tdotrai+50; toado[i].y:=sogia+50*qqq; toadoo[k].x:=30+tdophai-100; toadoo[k].y:=sogia+50*qqq; i:=i+1;k:=k+1;qqq:=qqq+1; end; for i:=1 to ssv do begin x11:=toado[i].x; y11:=toado[i].y; setcolor(4); circle(x11,y11,7); circle(x11,y11,6); setfillstyle(1,15); floodfill(x11,y11,4); setcolor(3); settextstyle(0,0,0); outtextxy(x11,y11-15,chr(48+i)); setcolor(4); line(tdotrai,tdoy,toado[i].x,toado[i].y); end; for k:=1 to sn do begin x22:=toadoo[k].x; y22:=toadoo[k].y; setcolor(4); circle(x22,y22,7); circle(x22,y22,6); setfillstyle(1,15); floodfill(x22,y22,4); setcolor(3); settextstyle(0,0,0); outtextxy(x22,y22-15,chr(48+k)); setcolor(4); line(tdophai,tdoy,toadoo[k].x,toadoo[k].y); end; setcolor(4); circle(tdotrai,tdoy,7); circle(tdotrai,tdoy,6); setfillstyle(1,15); floodfill(tdotrai,tdoy,4); setcolor(3); settextstyle(0,0,0); settextjustify(tdotrai,tdoy); outtextxy(tdotrai,tdoy-15,'s'); setcolor(4); circle(tdophai,tdoy,7); circle(tdophai,tdoy,6); setfillstyle(1,15); floodfill(tdophai,tdoy,4); setcolor(3); settextstyle(0,0,0); settextjustify(tdophai,tdoy); outtextxy(tdophai,tdoy-15,'t'); for i:=1 to ssv do begin for j:=1 to sn do if C^[i,j]=1 then begin setcolor(4); line(toado[i].x,toado[i].y,toadoo[j].x,toadoo[j].y); end; end; end; (*========================================================*) procedure toado2; var i,j,k,m,x11,y11,x22,y22:integer; tdotrai,tdophai,qqq,tdoy,temp,sogia:word; begin setcolor(15); tdotrai:=getmaxx div 2+15;tdophai:=getmaxx -15; tdoy:=getmaxy div 2; i:=1;k:=1;qqq:=1; while (qqq<=ssv+sn) do begin if temp<6 then sogia:=100 else sogia:=50; toado[i].x:=30+tdotrai+50; toado[i].y:=sogia+50*qqq; toadoo[k].x:=30+tdophai-80;; toadoo[k].y:=sogia+50*qqq; i:=i+1;k:=k+1;qqq:=qqq+1; end; for i:=1 to ssv do begin x11:=toado[i].x; y11:=toado[i].y; setcolor(4); circle(x11,y11,7); circle(x11,y11,6); setfillstyle(1,15); floodfill(x11,y11,4); setcolor(3); settextstyle(0,0,0); settextjustify(100,100); outtextxy(x11,y11-15,chr(48+i)); setcolor(4); line(tdotrai,tdoy,toado[i].x,toado[i].y); end; for k:=1 to sn do begin x22:=toadoo[k].x; y22:=toadoo[k].y; setcolor(4); circle(x22,y22,7); circle(x22,y22,6); setfillstyle(1,15); floodfill(x22,y22,4); setcolor(3); settextstyle(0,0,0); settextjustify(100,100); outtextxy(x22,y22-15,chr(48+k)); setcolor(4); line(tdophai,tdoy,toadoo[k].x,toadoo[k].y); end; setcolor(4); circle(tdotrai,tdoy,7); circle(tdotrai,tdoy,6); setfillstyle(1,15); floodfill(tdotrai,tdoy,4); setcolor(3); settextstyle(0,0,0); settextjustify(tdotrai,tdoy); outtextxy(tdotrai,tdoy-15,'s'); setcolor(4); circle(tdophai,tdoy,7); circle(tdophai,tdoy,6); setfillstyle(1,15); floodfill(tdophai,tdoy,4); setcolor(3); settextstyle(0,0,0); settextjustify(tdophai,tdoy); outtextxy(tdophai,tdoy-15,'t'); for i:=1 to ssv do begin for j:=1 to sn do if F^[i,j]=1 then begin setcolor(4); line(toado[i].x,toado[i].y,toadoo[j].x,toadoo[j].y); end; end; end; (*======================================================*) procedure Mophong; begin TransMatrixFlow; max_flow; TransresultM; Initgr; display; { setbkcolor(8);} Outtextxy(140,45,'GRAPH INPUT'); Outtextxy(478,45,'GRAPH OUTPUT '); toado1; toado2; READLN; closegraph; end; (*-----------------------------------------------------*) procedure phannhom; begin {if ok then begin} TransMatrixFlow; max_flow; TransresultM; initgr; display; Outtextxy(140,45,'MA TRAN A BIEU DIEN MANG G '); Outtextxy(478,45,'LUONG CUC DAI TRONG MANG G '); vechu1; { end else begin initgr; display; setcolor(4); outtextxy(50,100,'Khong phan nhom duoc'); end;} READLN; closegraph; end; (*=========================================================*) (* CHON LENH LAM VIEC *) (*=========================================================*) function menu(c:byte):word; var cmd:word; begin if c=68 then begin cmd:=menubar($70,$20,1); {(*$20,$70 mau nen:3bit cao, mau chu :4 bit thap*)} case cmd of IDNEW : newfile; IDOPEN : openfile; IDSAVE : savefile; IDPNHOM: phannhom; IDMOPHONG :Mophong; IDABOUT :about; end; repaint; end; menu:=cmd; end; (*-----------------------------------------------------------------------*) procedure appinit; begin init; textmode(C80); repaint; end; (*------------------------------------------------------------------------*) var cmd:word; begin appinit; repeat cmd:=menu(port[$60]); until (cmd=0)or(cmd=IDEXIT)OR(port[$60]=1) ; finish; end. II. MỘT SỐ GIAO DIỆN CHÍNH CỦA CHƯƠNG TRÌNH 1. Giao diện chính 2. Giao diện nhập ma trân A biểu diễn mạng G = (V,E) với khả năng thông qua các cung các đỉnh. 2. Giao diện biểu diễn mạng với luồng cực đại Chương 2 BÀI TOÁN LUỒNG CỰC ĐẠI VỚI KHẢ NĂNG THÔNG QUA CÁC CUNG – CÁC ĐỈNH Bài toán luồng cực đại trong mạng là một trong số những bài toán tối ưu trên đồ thị tìm được những ứng dụng rộng rãi trong thực tế cũng như những ứng dụng thú vị trong lý thuyết tổ hợp. Bài toán được đề xuất vào đầu những năm 1950, và gắn liền với tên tuổi của hai nhà bác học Mỹ là Ford và Fulkerson. Bài toán luồng cực đại trong mạng có nhiều ứng dụng trong thực tế như: Bài toán xác định cường độ dòng lớn nhất của dòng vận tải giữa hai nút của một bản đồ giao thông, bài toán tìm luồng dầu lớn nhất có thể bơm từ tàu chở dầu vào bể chứa của một hệ thống đường ống dẫn dầu…Ngoài ra, ứng dụng của bài toán còn để giải các bài toán như: Bài toán đám cưới vùng quê, bài toán về hệ thống đại diện chung, bài toán phân nhóm sinh hoạt, bài toán lập lịch cho hội nghị …Trong phạm vi đề tài này tôi sẽ trình bày “bài toán luồng cực đại trong mạng với khả năng thông qua các cung các đỉnh” và phải nhờ thuật toán của Ford và Fulkerson để giải bài toán đặt ra và nêu một số ứng dụng của bài toán. I. PHÁT BIỂU BÀI TOÁN 1.Bài toán Giả xử trong đồ thị G = (V,E), ngoài khả năng thông qua của các cung c(u,v), ở mỗi đỉnh v Î V còn có khả năng thông qua của đỉnh là d(v), và đòi hỏi tổng luồng đi vào đỉnh v không còn vượt quá d(v), tức là Cần phải tìm luồng cực đại giữa s và t trong mạng như vậy. Xây dựng một mạng G’ sao cho: mỗi đỉnh v của G tương ứng với hai đỉnh v+, v- trong G’, mỗi cung (u,v) trong G ứng với cung (u,v+) trong G’, mỗi cung (v,w) trong G ứng với cung (v-,w+) trong G’. Ngoài ra, mỗi cung (v+,v-) trong G’ có khả năng thông qua là d(v), tức là bằng khả năng thông qua của đỉnh v trong G. 2. Giải quyết bài toán Từ mạng G = (V,E) khả năng thông qua các cung và các đỉnh. Ta sẽ giải quyết theo hai bước sau: 10 Xác định mạng G’. 20 Tìm luồng cực đại trong mạng G’. Bắt đầu từ luồng zero với khả năng thông qua cung. Thí dụ 1. Hình 1a cho ví dụ mạng G với khả năng thông qua ở cung và đỉnh. Hình 1b là mạng G’ tương ứng chỉ có khả năng thông qua ở các cung. C[u,v] C[v,t] C[s,v] C[u,t] C[s,u] t dt v dv u du s ds (a) C[v,t] C[u,t] C[s,v] C[s,u] t- dt t+ C[u,v] v- dv v+ u- du u+ s- ds s+ (b) Hình 1 Do luồng đi vào đỉnh v+ phải đi qua cung (v+,v-) với khả năng thông qua d(v), nên luồng cực đại trong G’ sẽ bằng luồng cực đại trong G với khả năng thông qua của các cung và đỉnh. Hai bước trên ta có thể biểu diễn dưới dạng sơ đồ thuật toán sau: Begin Mạng G Mạng G’ Luồng cực đại trên G’ End 3. Ma trận biểu diễn đồ thị của bài toán luồng cực đại. 3.1 Biểu diễn mạng G với khả năng thông qua các cung - đỉnh Giả sử mạng G = (V,E), |V| = n. Ta có thể biểu diễn bởi ma trận trọng số A cấp n x n như sau: di ,nếu i = j c[i,j] ,nếu [i,j] Î E 0 ,nếu [i,j] Ï E A = ( aij ) = Trong đó: di là khả năng thông qua đỉnh i; C[i,j] khả năng thông qua cung [i,j]. 3.2 Biểu diễn mạng G’ tương ứng với mạng G Mạng tương ứng với G = (V,E), |V | = n là mạng G’ = (V’,E’), |V’| = 2 |V |, |E’| = 2 |E | - 1. Được biểu diễn thông qua ma trận A’ cấp (2n x 2n) như sau: A’ = ( a’ij ) = nếu i = j c[i,j] nếu [i,j] Î E’ Thí dụ 2. Như thí dụ trên có mạng G như sau: s[7] 1 3 2 4 5 t[6] v[8] u[6] Ta có ma trận biểu diễn mạng G : A = s u v t 7 5 2 0 s 0 6 1 4 u 0 0 8 3 v 0 0 0 6 t Tương tự từ mạng G’: t- 6 t+ 4 3 1 v- 8 v+ u- 6 u- 5 s- 7 2 s+ Ta có ma trận biểu diễn mạng G’ như sau: A’ = s+ s- u+ u- v+ v- t+ t- 0 7 0 0 0 0 0 0 s+ 0 0 5 0 2 0 0 0 s- 0 0 0 6 0 0 0 0 u+ 0 0 0 0 1 0 4 0 u- 0 0 0 0 0 8 0 0 v+ 0 0 0 0 0 0 3 0 v- 0 0 0 0 0 0 0 6 t+ 0 0 0 0 0 0 0 0 t- Áp dụng T.T Ford-Fulkerson tìm luồng cực đại cho mạng G’ ta được mạng cực đại và ma trận biểu diễn nó như sau: C = s+ s- u+ u- v+ v- t+ t- 0 6 0 0 0 0 0 0 s+ 0 0 4 0 2 0 0 0 s- 0 0 0 4 0 0 0 0 u+ 0 0 0 0 0 0 4 0 u- 0 0 0 0 0 2 0 0 v+ 0 0 0 0 0 0 2 0 v- 0 0 0 0 0 0 0 6 t+ 0 0 0 0 0 0 0 0 t- Với Val(f*) = 6 4. Bài toán luồng cực đại trong mạng Cho mạng G=(V,E). Hãy tìm luồng f* trong mạng với giá trị luồng val(f*) là lớn nhất . Luồng như vậy ta sẽ gọi là luồng cực đại trong mạng. 4.1. Thuật toán Ford – Fulkerson tìm luồng cực đại trong mạng Bắt đầu từ mạng với luồng trên tất cả các cung bằng 0 ( ta sẽ gọi luồng như vậy là luồng không ), và lặp lại bước lặp sau đây cho đến khi thu được luồng mà đối với nó không còn luồng tăng: Thuật toán 10 Xuất phát từ một luồng chấp nhận được f. 20 Tìm một đường đi tăng luồng P. Nếu không có thì thuật toán kết thúc. Nếu có, tiếp bước 3 dưới đây. 30 Nếu d(P) = +¥ thuật toán kết thúc. Trong đó d(P) - Lượng luồng tăng thêm, hay nói khác là làm sự tăng luồng (flow augmentation) dọc theo đường đi tăng luồng P một lượng thích hợp mà các ràng buộc của bài toán vẫn thoả. Sơ đồ của thuật toán Ford – Fulkerson có thể mô tả trong thủ tục sau đây: Procedure Max_Flow; (* Thuật toán Ford – Fulkerson *) begin (* Khởi tạo: Bắt đầu từ luồng với giá trị 0 *) for u Î V do for v Î V do f(u,v):=0; Stop:=false; While not Stop do if then else Stop:= true; end; Để tìm đường tăng luồng trong Gf có thể sử dụng thuật toán tìm kiếm theo chiều rộng ( hay thuật toán tìm kiếm theo chiều sâu) bắt đầu từ đỉnh s, trong đó không cần xây dựng tường minh đồ thị Gf. Ford- Fulkerson đề nghị thuật toán gán nhãn chi tiết sau đây để giải bài toán luồng trong mạng. Thuật toán bắt đầu từ luồng chấp nhận được nào đó trong mạng ( có thể bắt đầu từ luồng không) sau đó ta sẽ tăng luồng bằng cách tìm các đường tăng luồng. Để tìm đường tăng luồng ta sẽ áp dụng phương pháp gán nhãn cho các đỉnh. Mỗi đỉnh trong quá trình thực hiện thuật toán sẽ ở một trong ba trạng thái: chưa có nhãn, có nhãn chưa xét, có nhãn đã xét. Nhãn của một đỉnh v gồm 2 phần và có một trong hai dạng sau: [+p(v), e(v)] hoặc [-p(v), e(v)]. Phần thứ nhất +p(v) (-p(v)) chỉ ra là cần tăng (giảm) luồng theo cung (p(v),v) cung (v,p(v)) còn phần thứ hai e(v) chỉ ra lượng lớn nhất có thể tăng hoặc giảm theo cung này. Đầu tiên chỉ có đỉnh s được khởi tạo nhãn và nhãn của nó là chưa xét, còn tất cả các đỉnh còn lại đều chưa có nhãn . Từ s ta gán cho tất cả các đỉnh kề với nó và nhãn của đỉnh s sẽ trở thành nhãn đã xét. Tiếp theo, từ mỗi đỉnh v có nhãn chưa xét ta lại gán nhãn cho tất cả các nhãn chưa có nhãn kề với nó và nhãn của đỉnh v trở thành nhãn đã xét. Quá trình sẽ được lặp lại cho đến khi hoặc là đỉnh t trở thành có nhãn hoặc là nhãn của tất cả các đỉnh có nhãn đều là đã xét nhưng đỉnh t vẫn chưa có nhãn. Trong trường hợp thứ nhất ta tìm được đường tăng luồng, còn trong trường hợp thứ hai đối với luồng đang xét không tồn tại đường tăng luồng ( tức là luồng đã là cực đại ). Mỗi khi tìm được đường tăng luồng, ta lại tăng luồng theo đường tìm được, sau đó xoá tất cả các nhãn và đối với luồng mới thu được lại sử dụng phép gán nhãn các đỉnh để tìm đường tăng luồng. Thuật toán sẽ kết thúc khi nào đối với luồng đang có trong mạng không tìm được đường tăng luồng. Thuật toán gán nhãn (The labeling algorithm) Gọi VT là tập mọi đỉnh đã gán nhãn nhưng chưa được thăm. Ta có thuật toán để tìm đường đi tăng luồng. Xuất phát với VT = {s} và s là nút đã đánh dấu duy nhất. Một bước lặp sẽ có VT hiện hành và gồm ba bước như sau. 10 Nếu t Î VT hoặc VT = Æ, thuật toán kết thúc. Ngược lại thì chọn một đỉnh u Î VT để thăm và đưa nó ra khỏi VT. Xét tất cả các đỉnh cạnh u, tức là xét mọi cung có dạng (u,v) và (v,u). 20 Nếu (u,v) Î E, F(u,v) < C(u,v) và v chưa gán nhãn thì gán nhãn nó và đưa v vào tập VT. 30 Nếu (v,u) Î E, F(v,u) > 0 và v chưa gán nhãn thì gán nhãn nó và đưa vào tập VT. Bây giờ ta xét kết quả của thuật toán gán nhãn. Nó có kết thúc hữu hạn hay không? Nhận xét rằng một đỉnh được vào tập VT chỉ khi chuyển từ chưa gán nhãn. Do đó một đỉnh chỉ được vào VT nhiều nhất là một lần. Mà mỗi bước lặp bỏ một đỉnh ra khỏi VT. Do đó, vì số đỉnh của mạng là hữu hạn, thuật toán phải kết thúc hữu hạn. Thí dụ 3. Áp dụng thuật toán Ford-Fullkerson tìm luồng cực đại bằng cách gán nhãn cho luồng zero sau: 7,0 4,0 12,0 3,0 4,0 5,0 9,0 5,0 7,0 4,0 6,0 c d e t b s a + Bước lặp 1: s ® a ® b ® t, d1 = 4 c(s+,4) 7,0 4,0 12,0 3,0 4,0 5,0 9,0 5,0 7,0 4,0 6,0 d(s+,7) e(d+,4) t(e+,2) b(a+,6) s (s,¥) a(s+,6) 7,4 4,4 12,0 3,0 4,0 5,0 9,0 5,0 7,0 4,0 6,4 c d e t b s a + Bước lặp 2: s ® a ® b ® c ® e ® t, d2 = 2 c(b+,2) 7,4 4,4 12,0 3,0 4,0 5,0 9,0 5,0 7,0 4,0 6,4 d(s+,7) e(c+,2) t(e+,2) b(a+,2) s (s,¥) a(s+,2) c 7,6 4,4 12,2 3,2 4,2 5,0 9,0 5,0 7,0 4,0 6,6 d e t b s a + Bước lặp 3: s ® c ® e ® t, d3 = 1 c(s+,4) 7,6 4,4 12,2 3,2 4,2 5,0 9,0 5,0 7,0 4,0 6,6 d(s+,7) e(c+,1) t(e+,1) b(a+,1) s (s,¥) a(s+,0) c 7,6 4,4 12,3 3,3 4,2 5,0 9,0 5,0 7,0 4,1 6,6 d e t b s a + Bước lặp 4: s ® d ® e ® t, d4 = 7 c(s+,3) 7,6 4,4 12,3 3,3 4,2 5,0 9,0 5,0 7,0 4,1 6,6 d(s+,7) e(d+,7) t(e+,7) b(a+,1) s (s,¥) a(s+,0) c 7,6 4,4 12,10 3,3 4,2 5,0 9,7 5,0 7,7 4,1 6,6 d e t b s a + Bước lặp 5: s ® c ® d ® e ® t, d5 = 2 c(s+,3) 7,6 4,4 12,10 3,3 4,2 5,0 9,7 5,0 7,7 4,1 6,6 d(c+,3) e(d+,2) t(e+,2) b(a+,1) s (s,¥) a(s+,0) c 7,6 4,4 12,12 3,3 4,2 5,0 9,9 5,2 7,7 4,3 6,6 d e t b s a + Bước lặp 6: Không còn đường tăng luồng nữa, Val(fmax) = 6+3+7 = 16. Sơ đồ thuật toán Ford-Fullkerson tổng quát False True False True Begin Mạng với luồng zero Stop:= False not Stop Find_Path Path-Found Tăng luồng Stop:= False Mạng với luồng cực đại End Sơ thuật toán Find_Path (Chi tiết) { Trả về TRUE nếu có đường tăng luồng } False False True False True False True C[u,v] >0 and (F[u,v]<C[u,v]) True Begin VT ¹ Æ u Ü VT; PathFound:= True v= t P[v]:= u; e[v]:=min{e[u],C[u,v]-F[u,v]} VT:= VT È {v} P[t]:= s ; e[t]:= +¥ VT = V\{s} For vÎV\VT C[v,u]>0 and F[v,u]>0 P[v]:= -u; e[v]:= min{e[u],F[v,u]} VT:= VT È {v} End False End PathFound:= False True v= t End Sơ đồ thuật toán tăng luồng (Inc_Flow) { Tăng luồng nếu có đường tăng } False False True True Begin f[v,u]:=f[v,u] + tang u:=v; v:=P[u] End u ¹ s v > 0 v:= -v f[v,u]:=f[v,u] - tang v:= P[t] ; u:= t ; tang:= e[t] Chương 3 CÀI ĐẶT BÀI TOÁN I.Cấu trúc dữ liệu trong chương trình 1. Input: Nhập mạng G = (V,E) với khả năng thông qua các cung các đỉnh. * Nhập số đỉnh: * Nhập ma trận A biểu diễn mạng G = (V,E) với khả năng thông qua các cung các đỉnh. Giả sử mạng G = (V,E), |V| = n. Ta có thể biểu diễn bởi ma trận trọng số A cấp n x n như sau: di ,nếu i = j c[i,j] ,nếu [i,j] Î E 0 ,nếu [i,j] Ï E A = ( aij ) = Trong đó: di là khả năng thông qua đỉnh i; C[i,j] là khả năng thông qua cung [i,j]. 2. Output * Ma trận A’ biểu diễn mạng G’ = (V’,E’) với khả năng thông qua các cung tương ứng. * Ma trận luồng cực đại của mạng đó * Giá trị luồng cực đại Val(f*). Mạng tương ứng với G = (V,E), |V | = n là mạng G’ = (V’,E’), |V’| = 2 |V |, |E’| = 2 |E | - 1. Được biểu diễn thông qua ma trận A’ cấp (2n x 2n) như sau: A’ = ( a’ij ) = 0 nếu i = j c[i,j] nếu [i,j] Î E’ Chú ý: Ta có thể Input ma trận A biểu diễn mạng G = (V,E) với khả năng thông qua các cung. Sau đó, Output ma trận và giá trị luồng cực đại của mạng đó. II. Tên một số hàm và thủ tục của chương trình nguồn Chương trình được viết bằng ngôn ngữ Pascal. Sau đây là tên một số hàm và thủ tục của chương trình nguồn: Procedure NMatranCD; { Thủ tục nhập ma trận biểu diễn mạng với khả năng thông qua các cung các đỉnh. } Procedure Find_PathL; { Thủ tục tìm đường tăng luồng } Procedure inc_FlowL; { Thủ tục tăng luồng } Procedure Max_Flow; { Thủ tục tăng luồng toàn bộ } Procedure NewfileL; { Thủ tục nhập ma trận biểu diễn mạng với khả năng thông qua các cung } ………………………………………………….. III.Một số giao diện của chương trình 1. Giao diện chính 2. Giao diện Input ma trận biểu diễn mạng G = (V,E) với khả năng thông qua các cung các đỉnh. 3. Giao diện Output ma trận biểu diễn mạng G’ = (V’,E’) với khả năng thông qua các cung tương ứng, ma trận luồng cực đại và giá trị luồng cực đại.

Các file đính kèm theo tài liệu này:

  • docThuật toán Ford- Fulkerson - Tìm lượng cực đại trong mạng.doc