Tải bản đầy đủ (.docx) (18 trang)

Lý thuyết đồ thị giải bài tập xác định thành phần liên thông thành phần liên thông mạnh thuật toán tarjan

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (3.27 MB, 18 trang )

TRƯỜNG ĐẠI HỌC KHOA HỌC TỰ NHIÊN
KHOA CÔNG NGHỆ THÔNG TIN – HỆ VB2 ĐÀO TẠO TỪ XA


BÁO CÁO
ĐỒ ÁN 1
GVHD Lý Thuyết: Đặng Trần Minh Hậu
GDHD Thực hành: Nguyễn Ngọc Thảo
LỚP: Lý Thuyết Đồ Thị - CSC00008
NHÓM 32




MỤC LỤC
A. Nội dung lý thuyết................................................................................... 3
Câu 1.............................................................................................................. 3
Câu 2.............................................................................................................. 3
B. Nội dung cài đặt
.......................................................................................................................
13


A. NỘI DUNG LÝ THUYẾT
Câu 1: Định nghĩa thành phần liên thơng mạnh (strongly connected component) trên đồ thị có
hướng
Một thành phần liên thơng mạnh của một đồ thị có hướng A là
+ Một tiểu đồ thị (tiểu đồ thị này có tính chất tối đại, tức là khơng một cạnh khác nào của đồ thị có
hướng cha (A) của nó tồn tại trong tiểu đồ thị này mà khơng làm mất đi tính chất liên thơng mạnh của
nó)
+ Tính chất của một tiểu đồ thị trong đồ thị có hướng là tính chất liên thơng mạnh (tất cả các cặp đỉnh


trong tiểu đồ thị đó có đường đi thuận tới nhau được và đường đi ngược lại).
Câu 2:
Ta có thể tìm thành phần liên thơng mạnh bằng nhiều phương pháp khác nhau (tham khảo Tài liệu
1). Chọn trình bày một giải thuật để tìm thành phần liên thơng mạnh. Phần trình bày cần nêu rõ
các vấn đề sàu: ý tưởng tổng quát của giải thuật, các bước thực hiện của giải thuật được thể hiện
bằng ví dụ cụ thể, và đánh giá ngắn về ưu điểm – khuyết điểm của giải thuật.
Giải thuật Tarjan cho các thành phần liên thông mạnh (Tarjan's strongly connected components algorithm)
a. Ý tưởng tổng quát của giải thuật
 Giải thuật Tarjan trên nền thuật tốn tìm đường theo chiều sâu DFS kết hợp với các tính chất trong
một thành phần liên thơng mạnh và các tính chất giữa các thành phần liên thơng mạnh trong một đồ
thị có hướng với nhau, mục đích để xác định từng thành phần liên thông mạnh trong một đồ thị có
hướng.
 Tính chất có thể được sử dụng
+ Trong một thành phần liên thông mạnh đỉnh nhỏ nhất có thể kết nối từ một đỉnh thành viên của
thành phần liên thông mạnh đều giống nhau và là đỉnh nhỏ nhất trong thành phần liên thơng mạnh đó.
+ Đỉnh kết nối nhỏ nhất này cố định và là duy nhất cho 1 thành phần liên thông mạnh (tức nếu qua
thành phần liên thơng mới sẽ có đỉnh kết nối nhỏ nhất mới)
+ Việc các liên kết “quay trở lại’’ không thể xuất hiện giữa thành phần liên thông mạnh này và thành
phần liên thông mạnh khác ,chỉ xuất hiện trong 1 thành phần liên thông mạnh.
=> Ghi lại đỉnh kết nối nhỏ nhất của một đỉnh và so sánh kết quả này với đỉnh cha của nó (node tỏa
nhánh) để tìm ra đỉnh kết nối nhỏ nhất từ các node con với nhau và với của node cha, tương tự theo dòng
đệ quy để lên node cha cao hơn.
 Sau khi hoàn thành các thủ tục ghi lại thứ tự đỉnh của đỉnh đang duyệt và ghi lại đỉnh kết nối nhỏ nhất
của nó ta có thể đưa đỉnh đó vào Stack
 Nếu đỉnh kết nối nhỏ nhất bằng chính số thứ tự đi qua của đỉnh thì ta có thể kết luận đỉnh đó là 1 node
bắt đầu cho một thành phần liên thông mạnh, và tất cả các đỉnh của thành phần liên thơng mạnh đó
đều có chung đỉnh kết nối nhỏ nhất
 Trên đường đi (của đệ quy) ta có thể in ra hoặc ghi lại (chứa) số thứ tự và các phần tử của từng thành
phần liên thông mạnh bằng cách lấy ra từ Stack
Các mảng và biến cần khởi tạo và chức năng gồm (ví dụ)

Tên
Loại
Chức năng
pointIndex
Chứa thứ tự duyệt qua của từng phần tử
- [] mảng một chiều int
- Chiều dài: bằng số đỉnh trong đồ thị


pointLowIndex

-[] mảng một chiều int
- Chiều dài: bằng số đỉnh trong đồ thị
-[] mảng một chiều int
- Chiều dài: xuất phát là 0 , độ dài +1 nếu
thêm 1 phần tử, -1 nếu giảm 1 phần tử
-[] mảng một chiều bool
- Chiều dài: bằng số đỉnh trong đồ thị

Stack

isOnStack

currentIndex

Số nguyên

(Tùy chọn) Count
(Tùy chọn)
MangTPLT


Số nguyên
-[] mảng

Chứa số thứ tự đỉnh nhỏ nhất mà đỉnh
đang xét liên kết
Chứa các phần tử đã gán pointIndex và
pointLowIndex
Chứa các đánh dấu true hoặc false xác
định một phần tử đã cho vào Stack hay
chưa
Số thứ tự hiện tại (sẽ tăng sau mỗi vòng
chạy Tarjan)
Biến đếm số thành phần liên thông
Chưa các thành phần liên thông, trong các
thành phần liên thơng chứa các đỉnh của
tplt đó.

Cũng như DFS, thuật toán Tarjan gồm 1 hàm main để khởi tạo thuật toán (duyệt các đỉnh v trong
tập đỉnh V của đồ thị) và một hàm Tarjan nhằm đánh số các phần tử đỉnh, đánh số các phần tử đỉnh
kết nối của các phần tử đỉnh trong đồ thị, cho vào stack
b. Các bước thực hiện của giải thuật được thể hiện bằng ví dụ cụ thể


Giả sử có đồ thị có hướng như bên dưới, áp dụng Tarjan để tìm các thành phần liên thơng mạnh
0

1

4


6

2

3

5

Bước thực hiện
Diễn giải
Bước 1: Set up các mảng và biến chứa - CurrentIndex = 0
thông tin về phần tử duyệt trong hàm - Cho từng đỉnh a của mọi đỉnh trong đồ thị
pointIndex[a] = -1
MainTarjan và set giá trị đầu tiên cho các
pointLowIndex[a] = -1
mảng và biến này cho tất cả các đỉnh
Stack = []
isOnStack[a] = false
- Hàm main có dạng (mã giả)

0

1

4

6

2


3

5


Bước 2: Chạy hàm Tarjan cho giá trị
đỉnh đầu là 0 duyệt đến hết đồ thị (check đã
duyệt chưa trong mảng pointIndex)

- pointIndex[0] = -1 => Tarjan(0)

0
0
0
T
x

pointIndex
pointLowIndex
isOnStack
Stack

Bước 3:
 Xét cho mỗi đỉnh con mà đỉnh đang


chạy Tarjan kết nối với nó.
Nếu đỉnh con chưa đi qua (pointIndex =




-1), chạy Tarjan trên đỉnh con đó.
Nếu đỉnh con đã đi qua (pointIndex ≠



-1) , tìm đỉnh nhỏ nhất mà 2 đỉnh cha
con đó kết nối (min poinLowIndex).
Khi đã xong việc xét các đỉnh con , tiến

1
-1
-1
F

0

1

4

6

2

3

2
-1

-1
F

3
-1
-1
F

5

4
-1
-1
F

5
-1
-1
F

6
-1
-1
F

Hàm Tarjan có dạng (mã giả)

hành so sánh giữa index và lowIndex
để check xem đỉnh đó có phải là đỉnh
nhỏ nhất của một thành phần liên thông

mạnh hay khơng, từ đó xuất ra các phần
tử trong Stack của thành phần liên
thơng mạnh đó.
Các bước chi tiết tại bước 3
Bước 3.1

- Đỉnh 0 kết nối với 1 => Chạy Tarjan cho 1 ,
5
1
4
0
pointIndex[0] = -1  Tarjan(1)

pointIndex
pointLowIndex
isOnStack
Stack

0
0
0
T
x

1
1
1
T
x


2
-1
-1
F

3
-1
-1
F

6

2

4
-1
-1
F

5
-1
-1
F

3
6
-1
-1
F



Bước 3.2

- Đỉnh 1 kết nối với 2,4,6  Chạy Tarjan cho 2,
1
0
pointIndex[2] = -1  Tarjan(2)

4

2

3

pointIndex
pointLowIndex
isOnStack
Stack

Bước 3.3

0
0
0
T
x

1
1
1

T
x

2
2
2
T
x

6
4
-1
-1
F

3
-1
-1
F

5
-1
-1
F

5

6
-1
-1

F

- Đỉnh 2 kết nối với 3  Chạy Tarjan cho 3,
0
pointIndex[3] = -1  Tarjan(3)

1

4

6

2

3

pointIndex
pointLowIndex
isOnStack
Stack

0
0
0
T
x

1
1
1

T
x

2
2
2
T
x

3
3
3
T
x

4
-1
-1
F

5
-1
-1
F

5

6
-1
-1

F

- Đỉnh 3 kết nối với 2,4
- Xét đỉnh 2 pointIndex[2] ≠ -1  đã có “quay lại’’ tức 2,3 cùng
nằm trong 1 thành phần liên thông. Cho pointLowIndex[3] =
min(pointLowIndex[3], pointIndex[2]) = 2
5
1
4
0

0 1
pointIndex
0 1
pointLowIndex
0 1
isOnStack
T T
Stack
x x
- Xét đỉnh 4, pointIndex[4] = -1
 Chạy Tarjan cho 4

pointIndex
pointLowIndex
isOnStack
Stack

0
0

0
T
x

1
1
1
T
x

2
2
2
T
x

3
3
2
T
x

4
-1
-1
F

0
2
2

2
T
x

36
3
2
T
x

3

2

6

5
-1
-1
F

6
-1
-1
F

1

4


4 25
4 -1
4 -1
T F
x

3
6
-1
-1
F

5


Bước 3.4

- Đỉnh 4 kết nối với 5  Chạy Tarjan cho 5,
pointIndex[5] = -1  Tarjan(5)

0

1

4

6

2


3

5

0 1 2 3 4 5 6
pointIndex
0 1 2 3 4 5 -1
pointLowIndex
0 1 2 2 4 5 -1
isOnStack
T T T T T T F
Stack
x x x x x x
- Đỉnh 5 kết nối với 4
- Xét đỉnh 4 pointIndex[4] ≠ -1  đã có “quay lại’’ tức 4,5 cùng
nằm trong 1 thành phần liên thông. Cho pointLowIndex[5] =
1
0
min(pointLowIndex[5], pointIndex[4]) = 4

4

2

3

6

0 1 2 3 4 5 6
pointIndex

0 1 2 3 4 5 -1
pointLowIndex
0 1 2 2 4 4 -1
isOnStack
T T T T T T F
Stack
x x x x x x
- Vì sau 5 khơng có đỉnh con nào khác ngồi 4  kết thúc vòng

Bước 3.5

lặp xét đỉnh con cho 5.
- Tiến hành check index và lowIndex của 5. Vì pointIndex[5] = 5
≠ pointLowIndex[5] = 4  End Tarjan cho 5.
- Sau khi end Tarjan(5)  quay lại Tarjan(4)
- Cho pointLowIndex[4] = min(pointLowIndex[4],
pointLowIndex [5]) = 4
- Vì 4 khơng có đỉnh con nào khác ngồi 5  kết thúc vịng lặp
xét đỉnh con cho 4
- Tiến hành check index và lowIndex của 4.
Vì pointIndex[4] = pointLowIndex[4] = 4
0
=> 4 là node nhỏ nhất trong 1 thành
6
phần liên thông  tiến hành xuất thành

1

4


2

3

phần liên thông 4,5
0 1 2 3 4 5 6
pointIndex
0 1 2 3 4 5 -1
pointLowIndex
0 1 2 2 4 4 -1
isOnStack
T T T T T T F
Stack
x x x x x x
Xuất thành phần liên thông và end Tarjan cho 4.
- Cho w = -1, tăng biến đếm thành phần liên thông
- Xét các phần tử trong stack (từ những phần tử cuối mảng đổ
lên), nếu khác 4 thì

5

5


1. Cho w = phần tử cuối cùng của stack
2. Tắt false cho w
3. Remove w từ Stack
4. Xuất ra hoặc đưa w vào 1 list các thành phần liên thông đã
chuẩn bị sẵn, tăng biến đếm thành phần liên thông
0

0
0
T
x

pointIndex
pointLowIndex
isOnStack
Stack

Bước 3.6

1
1
1
T
x

2
2
2
T
x

3
3
2
T
x


4
4
4
F

5
5
4
F

6
-1
-1
F

- Sau khi end Tarjan(4)  quay lại Tarjan(3)
- Cho pointLowIndex[3] = min(pointLowIndex[3],
pointLowIndex [4]) = 2
- Vì 3 khơng có đỉnh con nào khác ngồi 2,4 => kết thúc vòng
lặp xét đỉnh con cho 3
- Tiến hành check index và lowIndex của 3
- Vì pointIndex[3] = 3 ≠ pointLowIndex[3] = 2 => End
Tarjan cho 3.
0
0
0
T
x

pointIndex

pointLowIndex
isOnStack
Stack
0

1

4

6

2

3

5

1
1
1
T
x

2
2
2
T
x

3

3
2
T
x

4
4
4
F

5
5
4
F

6
-1
-1
F


Bước 3.7

- Sau khi end Tarjan(3)  quay lại Tarjan(2)
- Cho pointLowIndex[2] = min(pointLowIndex[2],
pointLowIndex [3]) = 2
- Vì 2 khơng có đỉnh con nào khác ngồi 3  kết thúc vòng lặp
xét đỉnh con cho 2
- Tiến hành check index và lowIndex của 2
- Vì pointIndex[2] = pointLowIndex[2] = 2

=> 2 là node nhỏ nhất trong 1 thành phần liên thông => Tiến
hành xuất thành phần liên thông 2,3
pointIndex
pointLowIndex
isOnStack
Stack

0
0
0
T
x

1
1
1
T
x

2
2
2
T
x

3
3
2
T
x


4
4
4
F

5
5
4
F

6
-1
-1
F

Xuất thành phần liên thông và end Tarjan cho 2.
- Cho w = -1, tăng biến đếm thành phần liên thông
- Xét các phần tử trong stack (từ những phần tử cuối mảng đổ
lên), nếu khác 2 thì
1. Cho w = phần tử cuối cùng của stack
2. Tắt false cho w
3. Remove w từ Stack
4. Xuất ra hoặc đưa w vào 1 list các thành phần liên thông đã
chuẩn bị sẵn
pointIndex
pointLowIndex
isOnStack
Stack


0
0
0
T
x

1
1
1
T
x

2
2
2
F

3
3
2
F

4
4
4
F

5
5
4

F

6
-1
-1
F

0

1

4

6

2

3

5


Bước 3.8

- Sau khi end Tarjan(2)  quay lại Tarjan(1)
- Cho pointLowIndex[1] = min(pointLowIndex[1],
pointLowIndex [2]) = 1  Hoàn thành xét đỉnh 2 cho 1
- Tiến hành xét đỉnh 4, 6
- Vì pointIndex[4] ≠ -1
=> Cho pointIndex[1] = min(pointLowIndex[1], pointIndex [4])

= 1 => Hoàn thành xét đỉnh 4 cho 1.
- Vì pointIndex[6] = -1  Chạy Tarjan(6)
5
1
4
0
2

6

pointIndex
pointLowIndex
isOnStack
Stack

0
0
0
T
x

1
1
1
T
x

2
2
2

F

3
3
2
F

4
4
4
F

5
5
4
F

3

6
6
6
T
x

- Đỉnh 6 có kết nối với 0 và 2
+ Xét 0
pointIndex[0] ≠ -1  Cho poinLowIndex[6] =
min(pointLowIndex[6],pointIndex[0]) = 0
+ Xét 2

pointIndex[2] ≠ -1  Cho poinLowIndex[6] =
min(pointLowIndex[6],pointIndex[2]) = 0
 Hoàn thành xét đỉnh 0,2 cho 6
- Vì 6 khơng có đỉnh con nào khác ngồi 0,2 => kết thúc vịng
lặp xét đỉnh con cho 6
- Tiến hành check index và lowIndex của 6
- Vì pointIndex[6] = 6 ≠ pointLowIndex[6] = 0 =>
=> End Tarjan cho 6.
pointIndex
pointLowIndex
isOnStack
Stack

0
0
0
T
x

1
1
1
T
x

2
2
2
F


3
3
2
F

4
4
4
F

5
5
4
F

6
6
0
T
x


Bước 3.9

- Sau khi end Tarjan(6)  quay lại Tarjan(1),
poinLowIndex[1] = min(pointLowIndex[1],pointLowIndex[6])
=0
- Vì 1 khơng có đỉnh con nào khác ngồi 2,4,6  kết thúc vịng
lặp xét đỉnh con cho 1.
- Tiến hành check index và lowIndex của 1.

- Vì pointIndex[1] = 1 ≠ pointLowIndex[1] = 0 => End
Tarjan cho 1
1
4
0
2

6

Bước 3.10

5

3

0 1 2 3 4 5 6
pointIndex
0 1 2 3 4 5 6
pointLowIndex
0 0 2 2 4 4 0
isOnStack
T T F F F F T
Stack
x x
x
- Sau khi end Tarjan(1)  quay lại Tarjan(0)
poinLowIndex[0] = min(pointLowIndex[0],pointLowIndex[1]) = 0
- Vì 0 khơng có đỉnh con nào khác ngồi 1  kết thúc vòng lặp
xét đỉnh con cho 0
- Tiến hành check index và lowIndex của 0. Vì pointIndex[0] =

pointLowIndex[0] = 0 => 0 là node nhỏ nhất trong 1 thành phần
liên thông => tiến hành xuất thành phần liên thông 0,1,6
0 1 2 3 4 5 6
pointIndex
0 1 2 3 4 5 6
pointLowIndex
0 0 2 2 4 4 0
isOnStack
T T F F F F T
Stack
x x
x
Xuất thành phần liên thông và end Tarjan cho 0.
- Cho w = -1, tăng biến đếm thành phần liên thông
- Xét các phần tử trong stack (từ những phần tử cuối mảng đổ
lên), nếu khác 2 thì
1. Cho w = phần tử cuối cùng của stack
2. Tắt false cho w
3. Remove w từ Stack
4. Xuất ra hoặc đưa w vào 1 list các thành phần liên thông đã
chuẩn bị sẵn

pointIndex
pointLowIndex
isOnStack

0
0
0
F


1
1
0
F

2
2
2
F

3
3
2
F

4
4
4
F

5
5
4
F

6
6
0
F



Stack

Bước 3.11

0

1

4

6

2

3

5

Khi đã end Tarjan 0, tiếp tục các phần tử khác trong vịng for của
hàm Main nếu đồ thì là đồ thị nhiều thành phần liên thông (trong
trường hợp ví dụ này cùng nằm trên 1 thành phần liên thơng)
nên có thể end for trong Main Tarjan.
Kết thúc thuật toán

c. Đánh giá ưu điểm và khuyết điểm của giải thuật Tarjan
Ưu điểm
- Chỉ 1 lần duyệt qua DFS, nhanh hơn thuật tốn Kosaraju
- Khơng cần đảo chiều các hướng mũi tên của đồ thị như

Kosaraju
- Dễ áp dụng

Khuyết điểm
- Chỉ xuất ra được kết quả khi tìm được node đỉnh
nhỏ nhất của một thành phần liên thông mạnh.
- Thứ tự các đỉnh trong thành phần liên thơng
mạnh tìm ra có thể bị ngược.

B. NỘI DUNG CÀI ĐẶT

Cho một đồ thị có hướng khơng có cạnh bội và khơng có cạnh khuyên . Danh sách kề biểu diễn
đồ thị được cho có định dạng như sau:
▪ Dịng đầu tiên chứa số nguyên n (n > 2) thể hiện số đỉnh củà đồ thị.
▪ n dòng tiếp theo lần lượt chứa thông tin danh sách kề củà đỉnh 0 đến đỉnh n-1.
▪ Danh sách kề của mỗi đỉnh i được biểu diễn bằng mi + 1 số ngun, trơng đó số nguyên đầu
tiên là số lượng đỉnh có cạnh nối xuất phát từ đỉnh i (tức là mi) và các số nguyên tiếp theo
là chỉ mục của những đỉnh kề (chỉ mục tính từ 0)
1) Xác định đồ thị được cho là liên thông mạnh, liên thông một phần, liên thông yếu hay
không
liên thông. Tham khảo Tài liệu [2].
2) Xác định các thành phần liên thơng mạnh có trong đồ thị. Với mỗi thành phần liên thông,
cho
biết chỉ mục củà các đỉnh thuộc về thành phần liên thơng đó. Tham khảo Tài liệu [3].


Kết quả bài làm
Xác định các loại đồ thị, xác định loại và thành phần liên thơng mạnh có trong đồ thị, phần
minh họa kết quả xuất
+ Đồ thị liên thơng mạnh: (hình 2.1.1)

I.

Hình 2.1.1
+ Đồ thị liên thơng từng phần (hình 2.1.2)


Hình 2.1.2
+ Đồ thị liên thơng yếu (hình 2.1.3)

Hình 2.1.3
+ Đồ thị khơng liên thơng (hình 2.1.4)

Hình 2.1.4

II.

Những ghi chú quan trọng


Chương trinh gồm 1 class chính (Program.cs) nơi gọi file.txt và xuất kết quả và các class chức năng.
Lưu ý copy đường dẫn vào hàm main để chương trình truy xuất vào đúng file (bơi màu vàng) *
*
ví dụ đường dẫn: @"D:\VB 2 KHTN\Lý thuyết đồ thị\Bai Tap\Đồ án
01\SOURCE\lienthongtungphan.txt"

Hình 2.1.5
Các class và hàm chức năng gồm có
Class
Bao gồm
Program

- Hàm Main: Hàm chính chạy chương trình
Graph
- struct AdjacencyList : Kiểu dữ liệu tự định nghĩa cho AdjacenyList
Handler
- Hàm InputAndStore : Đọc danh sách kề vào chương trình
- Hàm ConvertToPathMatrix: Chuyển đổi AdjacencyList qua PathMatrix
- Hàm ConvertToUndirectedGraph: Chuyển đổi đồ thị dạng AdjacencyList qua
AdjacencyMatrix
DFS
Tarjan
(Hình 2.1.7)
Connected
Component
TypeCheck
(Hình 2.1.6)

- Hàm DFSFindPath, DFSMainFindPath: DFS tìm đường đi
- Hàm DFSFindComponents, DFSPrintComponents, DFSMainFindComponents: DFS
xác định liên thông hay khơng liên thơng
- Hàm Min: Tìm Min 2 số a,b
- Hàm MainTarJan, TarjanSCC, PrintSCCArr: thuật toán Tarjan xác định thành phần liên
thơng mạnh
- Hàm connectedComponentTypeCheck: hàm chính xác định loại thành phần liên thông
- Hàm strongConnectedComponentCheck, unilaterallyConnectedComponentCheck,
noConnectedComponentCheck: check các trường hợp mạnh , từng phần và không liên
thông.
=> Hàm tổng (connectedComponentTypeCheck) sẽ check loại đồ thị liên thông nếu
không phải 3 loại trên sẽ là đồ thị liên thông yếu



Hình 2.1.6


Hình 2.1.7



×