Đồ án giải thuật và lập trình trường đại học bách khoa đà nẵng khoa công nghệ thông tin, đề tài luồng cực đại trên mạng. Đồ án cấu trúc giải thuật và lập trình trường đại học bách khoa đà nẵng khoa công nghệ thông tin, đề tài tìm luồng cực đại trên mạng
Trang 1ĐẠI HỌC ĐÀ NẴNG ĐẠI HỌC BÁCH KHOA KHOA CÔNG NGHỆ THÔNG TIN
ĐỒ ÁN
CẤU TRÚC DỮ LIỆU VÀ GIẢI THUẬT
Đề tài 2:
Tìm luồng cực đại trên mạng
GVHD : PHAN THANH TAO SVTH : VÕ VĂN HÙNG LỚP : 17T2
NHÓM : 17.12B
Đà Nẵng 12-2019
Trang 2LỜI MỞ ĐẦU
Luồng cực đại là một trong những bài toán tối ưu trên đồ thị tìm được những
ứng dụng rất rộng rãi trong cả thực tế cũng như 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 2 nhà toán học Mỹ Lester Randolph Ford và Delbert Ray Fulkerson [1] Bài toán tìm luồng cực đại được áp
dụng nhiều trong thực tiễn cuộc sống như: tính toán lượng nước lớn nhất có thể vận chuyển giữa hai địa điểm (điểm phát và điểm thu) trong một mạng ống nước; xác định cường độ dòng vận tải lớn nhất giữa hai nút của hệ thống giao thông trong thành phố hoặc bài toán ghép cặp hay bài toán lập lịch
Trong báo cáo này, em sẽ trình bày bài toán tìm luồng cực đại trong mạng sử
dụng thuật toán Ford-Fulkerson để giải quyết bài toán đặt ra
Em xin chân thành cảm ơn thầy Phan Thanh Tao đã hướng dẫn và giúp đỡ em
trong suốt quá trình nghiên cứu và tìm hiểu để hoàn thành đề tài này Rất mong nhận được sự góp ý của thầy (cô) để đề tài của em được hoàn thiện hơn
Trang 3MỤC LỤC
LỜI MỞ ĐẦU 2
MỤC LỤC 3
DANH MỤC HÌNH VẼ 4
1 GIỚI THIỆU ĐỀ TÀI 5
2 CƠ SỞ LÝ THUYẾT 5
2.1 Ý tưởng 5
2.2 Cơ sở lý thuyết 5
3 TỔ CHỨC CẤU TRÚC DỮ LIỆU VÀ THUẬT TOÁN 7
3.1 Phát biểu bài toán 7
3.2 Cấu trúc dữ liệu 8
3.3 Thuật toán 8
4 CHƯƠNG TRÌNH VÀ KẾT QUẢ 9
4.1 Tổ chức chương trình 9
4.2 Ngôn ngữ cài đặt 13
4.3 Kết quả 13
4.3.1 Giao diện chính của chương trình 13
4.3.2 Kết quả thực thi của chương trình 14
4.3.3 Nhận xét 15
5 KẾT LUẬN VÀ HƯỚNG PHÁT TRIỂN 15
5.1 Kết luận 15
5.2 Hướng phát triển 15
TÀI LIỆU THAM KHẢO 16
Trang 4DANH MỤC HÌNH VẼ
Hình 1: Mạng G……….…….6
Hình 2: Mạng G và luồng trên mạng G……… ……… 6
Hình 3: File input.txt……… 8
Hình 4: File output.txt……… … 8
Hình 5: Giao diện chính của chương trình……… 14
Hình 6: Đồ thị và luồng cực đại của mạng G……… 14
Hình 7: File output.txt……… 15
Trang 51 GIỚI THIỆU ĐỀ TÀI
“Tìm luồng cực đại trên mạng”
Nhiều bài toán quy hoạch tuyến tính có thể quy về bài toán làm cực tiểu phí tổn vận chuyển hàng trong một mạng (gồm các nút và các cung đường) sao cho đảm bảo được các nhu cầu ở một số nút khi đã biết nguồn cung cấp tại một số nút khác Các bài
toán như vậy được gọi là các bài toán luồng trên mạng (network flow problem) hoặc bài toán chuyển vận (transshipment problem) Đây là lớp bài toán quan trọng nhất và
hay gặp nhất trong quy hoạch tuyến tính Lớp này bao gồm các bài toán quen thuộc trong thực tế như: bài toán vận tải, các bài toán mạng điện và mạng giao thông, các bài toán quản lý và phân bổ vật tư, bài toán đường ngắn nhất, bài toán luồng cực đại…
Bài toán tìm luồng cực đại là một bài toán tối ưu trên đồ thị mang tính thực tiễn,
ứng dụng cao trong cuộc sống như: tính toán lưu lượng nước (dầu) lớn nhất có thể vận chuyển giữa hai địa điểm (điểm phát và điểm thu) trong một mạng ống nước (dầu); xác định cường độ dòng vận tải lớn nhất giữa hai nút của hệ thống giao thông trong thành phố… Vì vậy, việc nghiên cứu về đề tài này góp phần đề ra những giải pháp tối ưu nhằm giải quyết những vấn đề về vận chuyển, giao thông…
2 CƠ SỞ LÝ THUYẾT
2.1 Ý tưởng
Xuất phát từ một luồng trước đó (bắt đầu từ luồng ban đầu với F = 0), ta tìm đường
đi không định hướng từ đỉnh phát đến đỉnh thu, tiến hành hiệu chỉnh giá trị luồng trên đường đi đó sao cho luồng mới có giá trị lớn hơn Lặp lại cho đến khi không còn tìm được đường tăng luồng thì thuật toán dừng và luồng ở bước lặp cuối cùng là luồng cực đại
Đường tăng luồng P có dạng:
- P: s→…→i→j→…→t thì (i,j) là cung thuận
- P: s→…→i←j→…→t thì (j,i) là cung nghịch
2.2 Cơ sở lý thuyết
2.2.1 Các khái niệm
1 Mạng[2]
- Mạng là đồ thị có hướng, có trọng số G=(V,E,C) thỏa mãn:
G liên thông yếu (nếu bỏ hướng các cạnh thì liên thông)
Có duy nhất một đỉnh s không có cung vào gọi là đỉnh phát
Có duy nhất một đỉnh t không có cung ra gọi là đỉnh thu
Mỗi cung (i,j) ∈ E được gán một số cij ≥ 0 gọi là khả năng thông qua của cung (i,j)
- Ví dụ:
Trang 6Hình 1 Mạng G
2 Luồng[2]
Cho mạng G=(V,E,C), trong đó V là tập đỉnh, E là tập cạnh và C là tập trọng
số
Luồng F trên mạng G là tập các giá trị {fij |(i, j) ∈ E} thỏa mãn:
- ∀(i,j) ∈ E: 0 ≤ fij ≤cij
- ∀ k ∉{s,t} (s là đỉnh phát, t là đỉnh thu):
(𝑖,𝑘)∈𝐸
(𝑘,𝑗)∈𝐸
Ví dụ:
Hình 2 Mạng G và luồng trên mạng G
Với đồ thị trên thì tập {fij}(giá trị được biểu diễn trong ngoặc đơn) là luồng:
fsa=8, fab=8, fbt=5, fbc=3, fsd=6, fsc=6, fcd=9, fdt=15
t s
13
12
9 6
5
15 6
3
t s
13(8)
12(8)
9(9) 6(6)
5(5)
15(15) 6(6)
3(3)
Trang 73 Giá trị luồng[2]
Cho mạng G=(V,E,C)
Giá trị của luồng F là tổng giá trị trên các cung đi ra từ đỉnh phát s, hoặc tổng giá trị trên các cung đi vào đỉnh thu t Kí hiệu là Vf
(𝑠,𝑘)∈𝐸
(𝑘,𝑡)∈𝐸
Luông cực đại trên mạng G là luồng có giá trị lớn nhất trong tất cả các luồng trên G
4 Lát cắt[2]
Cho mạng G =(V,E,C)
Lát cắt S= (V1,V2) là một phân hoạch tập đỉnh V của mạng G thành hai tập V1 và V2 =V\V1, trong đó s ∈ V1, t ∈ V2
Khả năng thông qua hay giá trị của lát cắt S = (V1,V2) là số c(V1,V2) = ∑cij với vi ∈ V1 và vj ∈ V2
Lát cắt có khả năng thông qua nhỏ nhất được gọi là lát cắt cực tiểu
2.2.2 Định lý Ford-Fulkerson[2]
Luồng cực đại bằng lát cắt cực tiểu
3 TỔ CHỨC CẤU TRÚC DỮ LIỆU VÀ THUẬT TOÁN
3.1 Phát biểu bài toán
Phát biểu bài toán: Cho mạng G =(V,E,C) với đỉnh phát s, đỉnh thu t và khả năng thông qua của mỗi cung là cij(i,j ∈ V) Trong tất cả các luồng có thể có trên mạng, tìm luồng có giá trị cực đại
Input: Số lượng đỉnh (node) của mạng G, đỉnh phát s và đỉnh thu t, ma trận trọng
số chứa khả năng thông qua của các cung cij chứa trong file input.txt, với:
- Hàng thứ nhất chứa số lượng đỉnh của mạng
- Đỉnh phát s ứng với đỉnh 0, đỉnh thu t ứng với đỉnh n-1
- n hàng tiếp theo (mỗi hàng chứa n số) là ma trận trọng số chứa khả năng
thông qua của các cung
Trang 8Hình 3 File input.txt
Output: Giá trị luồng cực đại Vmax(f), và ma trận trọng số F là các luồng cực đại trên các cung chứa trong file output.txt, với:
- Hàng thứ nhất là giá trị luồng cực đại Vmax(f)
- n hàng tiếp theo (mỗi hàng chứa n số) là ma trận trọng số chứa các luồng
cực đại trên các cung
Hình 4 File output.txt
3.2 Cấu trúc dữ liệu
- Xây dựng một lớp Node để biểu diễn các thuộc tính của đỉnh như trạng thái,
nhãn, đỉnh kề trước của nó trong luồng P
- Sử dụng hai file input.txt và output.txt để nhập dữ liệu và xuất kết quả
- Sử dụng 2 mảng hai chiều lần lượt biểu diễn khả năng thông qua của các cung
trên mạng và luồng trên cung
3.3 Thuật toán
a Thuật toán Ford-Fulkerson[2]
Trang 9Thuật toán Ford-Fulkerson để tìm luồng cực đại F trên mạng G = (V, E, C) với đỉnh phát s và đỉnh thu t gồm các bước sau:
Bước 1: Khởi tạo luồng F=0; ∀(i,j) ∈ E: fij=0
Bước 2: Lặp cho đến khi hết đường tăng luồng:
- Tìm đường tăng luồng P: s→t với lượng tăng luồng δ:
+ Đặt nhãn cho s là ∞
+ Lặp cho đến khi đỉnh t có nhãn δt: khi đỉnh vi vừa có nhãn thì đánh nhãn lại mọi đỉnh vj kề vô hướng với vI nếu thỏa mãn một trong hai trường hợp sau:
Nếu có cung (i,j) và cij – fij>0(chưa bão hòa) thì đánh nhãn của đỉnh j
là δj = min(δi,cij – fij), nạp cung thuận vào P
Nếu có cung (j,i) và fij>0 thì nhãn của đỉnh j là δj = min(δi, fij), nạp cung nghịch vào P
- Tăng luồng dọc theo P một lượng δ:
+ Khi đỉnh t vừa có nhãn δt thì có lượng tăng luồng là δ = δt; ngược lại nếu không đánh nhãn được đỉnh t thì hết đường tăng luồng(thuật toán dừng)
+ Tăng luồng dọc theo P một lượng δ theo công thức:
f’ij = fij + δ , nếu (i,j) là cung thuận
f’ij = fij - δ , nếu (j,i) là cung nghịch
b Độ phức tạp của thuật toán Ford-Fulkerson
Xét mạng G = (V,E,C), khi khả năng thông qua của các cung là số tự nhiên, thì luồng thu được có giá trị cũng là số tự nhiên:
- Mỗi đường tăng luồng được tìm ra trong khoảng thời gian bị chặn bởi
O(E) vì có mạng G có E cạnh
- Mỗi lần tăng luồng chỉ tăng một lượng có giá trị nguyên dương nên lượng
nhỏ nhất có thể tăng là 1 Vậy nếu giá trị của luồng cực đại là F thì số lần tăng luồng bị chặn bởi F/1 = F
Vậy thời gian chạy của thuật toán Ford-Fulkerson bị chặn bởi O(E*F)
4 CHƯƠNG TRÌNH VÀ KẾT QUẢ
4.1 Tổ chức chương trình
File Node.h
class Node {
int status; // 0: chua gan nhan; 1: da gan nhan; -1: dua dinh vao duong tang luong
int before; // dinh ke truoc tren duong tang luong
int label; // nhan cua dinh
public :
Node();
~Node();
void resetnode( int = 0 , int l = 0, int b = -1);
void setstatus();
Trang 10int getlabel();
};
File Node.cpp
#include "Node.h"
Node::Node() {
this ->status = 0;
this ->label = 0;
this ->before = -1;
}
Node::~Node(){
}
void Node::resetnode( int , int , int ) {
this ->status = s ;
this ->label = l ;
this ->before = b ;
}
int Node::getstatus() {
return this ->status;
}
void Node::setstatus() {
this ->status = -1;
}
int Node::getlabel() {
return this ->label;
}
int Node::getbefore() {
return this ->before;
}
File Program.cpp
#include <iostream>
#include <iomanip>
#include <fstream>
#include "Node.h"
using namespace std;
int n;
Node* node;
int s, t;
int **c;
int **f;
int F;
void Inputdata()
{
ifstream file_in;
file_in.open( "input.txt" , ios::in);
//kiem tra co mo duoc file, neu khong thi nem ngoai le
if (file_in.fail()) {
throw "Can't open the input file" ; }
Trang 11//nhap so luong dinh va kha nang thong qua cua cac cung
file_in >> n;
c = new int * [n];
for ( int i = 0; i < n; i++)
{
c[i] = new int [n];
for ( int j = 0; j < n; j++)
file_in >> c[i][j];
}
file_in.close();
}
void Initialize()
{
//khoi tao luong ban dau bang 0
f = new int * [n];
for ( int i = 0; i < n; i++)
{
f[i] = new int [n];
for ( int j = 0; j < n; j++)
f[i][j] = 0;
}
//Khoi tao cac dinh
node = new Node[n];
s = 0;
t = n - 1;
//Khoi tao gia tri luong cuc dai
F = 0;
}
void Max_Flow()
{
// Lap cho den khi het duong tang luong
while ( true ) {
//Xoa nhan tat ca cac dinh va gan nhan cho dinh phat la vo cung
for ( int i = 1; i < n; i++) {
node[i].resetnode();
} node[s].resetnode(1, 1000, -1);
//Lap cho den khi dinh t co nhan
while (node[t].getstatus()==0) {
//Tim dinh j co nhan de dua vao duong tang luong
int j;
for (j = 0; j < n; j++) {
if (node[j].getstatus() == 1) {
break ; }
}
if (j == n) return ; //Het duong tang luong,thuat toan dung
Trang 12for ( int i = 1; i < n; i++) {
if (node[i].getstatus() == 0) {
//Cung dang (j,i) va chua bao hoa
if (c[j][i] > 0 && (c[j][i] - f[j][i] > 0)) {
int flow;
if (node[j].getlabel()>c[j][i]-f[j][i])
flow = c[j][i] - f[j][i];
else flow = node[j].getlabel();
node[i].resetnode(1, flow, j);
}
//Cung dang (i,j)
if (c[i][j] > 0 && f[i][j] > 0) {
int flow;
if (node[j].getlabel() > f[i][j])
flow = f[i][j];
else
flow = node[j].getlabel();
node[i].resetnode(1, flow, j);
} }
} }
// Tang gia tri cua luong
int delta = node[t].getlabel();
F += delta;
// Hieu chinh luong doc theo duong tang luong
int after = t;
while (after != s) {
int before = node[after].getbefore();
if (c[before][after] > 0) f[before][after] += delta;
if (c[after][before] > 0) f[before][after] -= delta;
after = before;
} }
}
void Outputdata()
{
ofstream file_out;
file_out.open( "output.txt" , ios::out);
file_out << F << endl;
for ( int i = 0; i < n; i++)
{
for ( int j = 0; j < n; j++) {
file_out << left << setw(3) << f[i][j];
} file_out << endl;
}
Trang 13file_out.close();
}
void Delete()
{
//Giai phong bo nho
for ( int i = 0; i < n; i++)
{
delete[] c[i];
delete[] f[i];
}
delete[] c;
delete[] f;
delete[] node;
}
int main()
{
try
{
Inputdata();
Initialize();
Max_Flow();
Outputdata();
Delete();
cout << "Result in ouput.txt" << endl;
}
catch ( const char * ex) {
cout << ex << endl;
}
system( "pause" );
return 0;
}
4.2 Ngôn ngữ cài đặt
Ngôn ngữ được sử dụng để cài đặt chương trình cho bài toán là C++ gồm 5 file: Node.h, Node.cpp, Program.cpp, input.txt, output.txt
4.3 Kết quả
4.3.1 Giao diện chính của chương trình
Chương trình không có giao diện tương tác người dùng, dữ liệu đầu vào được nhập
từ file input.txt và kết quả được xuất ra file output.txt
Trang 14Hình 5 Giao diện chính của chương trình
4.3.2 Kết quả thực thi của chương trình
- Kết quả thực hiện bằng tay:
Hình 6 Đồ thi và luồng cực đại của mạng G
- Kết quả thực hiện bằng chương trình:
t s
13(8)
12(8)
9(9) 6(6)
5(5)
15(15) 6(6)
3(3)
Trang 15Hình 7 File output.txt
4.3.3 Nhận xét
Sau khi so sánh kết quả thực hiện bằng tay và kết quả sau khi chạy chương trình thì ta thấy chương trình đã tìm được đúng luồng cực đại Tuy nhiên, ta chỉ thấy được kết quả thực thi chương trình trong file output.txt nhưng chưa quan sát được toàn bộ quá trình tìm đường tăng luồng
5 KẾT LUẬN VÀ HƯỚNG PHÁT TRIỂN
5.1 Kết luận
Thuật toán Ford-Fulkerson đã tìm được đúng luồng cực đại trên mạng Từ đây ta
có thể áp dụng thuật toán này để giải quyết nhiều vấn đề thực tiễn như cung cấp nước sinh hoạt, tìm luồng vận tải lớn nhất…
5.2 Hướng phát triển
Cần phải thiết kế thêm phần giao diện để người dùng có thể quan sát được quá trình xác định đường tăng luồng cũng như quá trình tăng luồng, khiến bài toán trở nên trực quan, hoàn thiện hơn
Trang 16TÀI LIỆU THAM KHẢO [1] Wikipedia:
https://vi.wikipedia.org/wiki/Lu%E1%BB%93ng_c%E1%BB%B1c_%C4%91% E1%BA%A1i
[2] Bài giảng Toán rời rạc( Dành cho sinh viên ngành Công nghệ thông tin ) –
2012 – Ths Phan Thanh Tao – Khoa CNTT – Đại học Bách Khoa – Đại học Đà Nẵng