Tải bản đầy đủ (.pdf) (74 trang)

(Luận văn thạc sĩ) thuật toán dijkstra fibonacci heap, thuật toán ACO tìm đường đi tối ưu và ứng dụng

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 (948.35 KB, 74 trang )

i

ĐẠI HỌC THÁI NGUYÊN
TRƯỜNG ĐẠI HỌC CÔNG NGHỆ THÔNG TIN&TRUYỀN THƠNG

NGHIÊM QUANG KHẢI

THUẬT TỐN DIJKSTRA FIBONACCI HEAP, THUẬT
TỐN ACO TÌM ĐƯỜNG ĐI TỐI ƯU VÀ ỨNG DỤNG

LUẬN VĂN THẠC SĨ KHOA HỌC MÁY TÍNH

THÁI NGUN - 2015

Số hóa bởi Trung tâm Học liệu – ĐHTN




ii

LỜI CAM ĐOAN
Tôi xin cam đoan luận văn này là kết quả nghiên cứu của riêng tơi. Các
thơng tin trích dẫn trong luận văn lấy từ các nguồn đã được công khai hoặc
đã được sự đồng ý của tác giả. Các kết quả nêu trong luận văn là kết quả
nghiên cứu riêng của tác giả luận văn, chưa có ai cơng bố trong các cơng
trình khác.

Thái Ngun, ngày 10 tháng 4 năm 2015
Học viên


Nghiêm Quang Khải

Số hóa bởi Trung tâm Học liệu – ĐHTN




iii

LỜI CẢM ƠN
Được sự phân công của trường Đại Học Công Nghệ Thông Tin Và
Truyền Thông - Đại Học Thái Nguyên và sự đồng ý của thầy giáo hướng dẫn
PGS - TS Đồn Văn Ban, tơi đã thực hiện đề tài “Thuật tốn Dijkstra
Fibonacci heap, thuật tốn ACO tìm đường đi tối ưu và ứng dụng”.
Để hoàn thành được đề tài này, tơi đã nhận được sự hướng dẫn tận
tình chu đáo của thầy hướng dẫn PGS – TS Đoàn Văn Ban, qua đây cho
phép tơi được bày tỏ lịng biết ơn chân thành tới Thầy và gia đình Thầy.
Tơi cũng xin được tỏ lòng cảm ơn đối với các thầy các cơ đã tận tình
hướng dẫn, giảng dạy lớp cao học 12G trong suốt hai năm qua, cám ơn
những tri thức các thầy cô đã truyền thụ, cảm ơn những tình cảm chân thành
các thầy cơ đã dành cho lớp.
Xin chân thành cám ơn những ý kiến đóng góp quý báu của các thầy cô
giáo và các bạn đồng nghiệp đối với đề tài này.
Chắc chắn đề tài này sẽ khơng tránh khỏi những thiếu sót, rất mong
nhận được các ý kiến đóng góp của các thầy cơ, các bạn đồng nghiệp và các
bạn độc giả, tôi xin chân thành cảm ơn.

Thái Nguyên, ngày 10 tháng 4 năm 2015
Học viên


Nghiêm Quang Khải

Số hóa bởi Trung tâm Học liệu – ĐHTN




iv

MỤC LỤC
LỜI CAM ĐOAN ....................................................................................................... i
LỜI CẢM ƠN ........................................................................................................... iii
MỞ ĐẦU .....................................................................................................................1
CHƯƠNG 1 ................................................................................................................4
CÁC THUẬT TỐN TÌM ĐƯỜNG ĐI TỐI ƯU TRÊN ĐỒ THỊ ............................4
1.1. Các khái niệm cơ bản của lý thuyết đồ thị .......................................................4
1.1.1. Định nghĩa đồ thị ......................................................................................4
1.1.2. Các thuật ngữ cơ bản .................................................................................5
1.1.3. Đường đi, chu trình, đồ thị liên thơng .......................................................6
1.1.4. Đồ thị có trọng số ......................................................................................7
1.2. Cây ....................................................................................................................8
1.3. Bài toán đường đi tối ưu trên đồ thị .................................................................8
1.4. Thuật toán Dijkstra.........................................................................................10
1.4.1. Phát biểu bài tốn.....................................................................................10
1.4.2.Mơ tả thuật tốn ........................................................................................10
1.5. Thuật tốn Dijkstra kết hợp với Fibonacci heap............................................11
1.5.1. Hàng đợi ưu tiên ......................................................................................11
1.5.2. Fibonacci heap .........................................................................................14
1.5.3. Sơ đồ thuật toán Dijkstra kết hợp với Fibonacci Heap ............................30
1.6. Kết luận chương .............................................................................................32

CHƯƠNG 2 ..............................................................................................................33
THUẬT TOÁN ĐÀN KIẾN GIẢI BÀI TỐN TÌM ĐƯỜNG ĐI TỐI ƯU ...........33
2.1. Từ kiến tự nhiên đến kiến nhân tạo ................................................................33
2.1.1. Kiến tự nhiên ...........................................................................................33
2.1.2. Kiến nhân tạo ...........................................................................................36
2.2. Thuật toán ACO tổng quát giải bài toán ngươi chào hàng ............................37
2.2.2. Thuật toán ACO tổng quát giải bài toán TSP ..........................................38
2.3. Các thuật toán ACO giải bài toán TSP ..........................................................39
2.3.1. Thuật toán AS ..........................................................................................40
2.3.2. Thuật toán ACS .......................................................................................42
2.3.3. Thuật toán Max-Min (MMAS) ................................................................44
2.4. Một số vấn đề trong việc áp dụng ACO tìm đường đi tối ưu .........................46
Số hóa bởi Trung tâm Học liệu – ĐHTN




v

2.4.1. ACO kết hợp với tìm kiếm cục bộ ...........................................................46
2.4.2. Thông tin heuristic ...................................................................................47
2.4.3. Số lượng kiến ...........................................................................................47
2.4.4. Tham số bay hơi ......................................................................................48
2.4.5. Một số đề xuất cải tiến .............................................................................48
2.5. Kết luận chương .............................................................................................49
CHƯƠNG 3 ..............................................................................................................50
ỨNG DỤNG THUẬT TOÁN DIJKSTRA FIBONACCI HEAP, THUẬT TỐN
ACO GIẢI CÁC BÀI TỐN TÌM ĐƯỜNG ĐI TRÊN MẠNG GIAO THÔNG....50
3.1. Ứng dụng Dijkstra Fibonacci heap ................................................................50
13.1.1. Phát biểu bài tốn 1 ..................................................................................50

3.1.2. Mơ hình hố bài tốn ...............................................................................50
3.1.3. Mơ tả input, output ..................................................................................50
3.1.4. Một số kiểu dữ liệu và các biến trong chương trình ...............................51
3.1.5. Một số hàm và thủ tục trong chương trình ..............................................52
3.1.6.Sơ đồ thuật toán ........................................................................................55
3.1.7. Các kết quả thực nghiệm giải bài toán 1..................................................56
3.2. Ứng dụng Dijkstra Fibonacci heap, ACO giải bài toán TSP mở rộng ..........58
3.2.1. Phát biểu bài toán 2..................................................................................58
3.2.2. Mơ hình hố bài tốn ...............................................................................58
3.2.3. Mơ tả input, output ..................................................................................58
3.2.4. Thuật toán tổng quát giải bài toán 2 ........................................................59
3.2.5. Một số hàm và thủ tục trong chương trình ..............................................59
3.2.6. Sơ đồ tổng quát của thuật toán giải bài toán 2. ........................................62
3.2.7. Các kết quả thực nghiệm giải bài toán 2..................................................63
3.3. Kết luận chương .............................................................................................65
KẾT LUẬN ...............................................................................................................67
TÀI LIỆU THAM KHẢO .........................................................................................69

Số hóa bởi Trung tâm Học liệu – ĐHTN




1

MỞ ĐẦU
Thuật tốn tìm đường đi tối ưu có nhiều ứng dụng trong thực tế, nếu
xây dựng được các thuật toán tốt sẽ giúp tiết kiệm được rất nhiều tiền bạc,
thời gian, công sức của con người. Một số bài tốn thực tế điển hình cần phải
sử dụng thuật tốn tìm đường đi tối ưu như:

- Tìm đường đi từ địa điểm A đến địa điểm B sao cho độ dài đường đi
là tối ưu hoặc nhanh nhất hoặc giá cước là nhỏ nhất.
- Tìm đường đi ngắn nhất xuất từ một điểm cho trước, đi qua một số
địa điểm cố định cho trước rồi quay trở về điểm xuất phát.
- Tương tự ta cũng có bài tốn tìm đường đi cho gói tin được gửi từ nút
A đến nút B trên mạng máy tính sao cho giá cước là nhỏ nhất hoặc nhanh
nhất...
- Tìm đường đi tối ưu cho robot, cho tên lửa hành trình, máy bay, phi
thuyền v.v cũng là những bài tốn đang được quan tâm.
Đã có nhiều cơng trình nghiên cứu về lĩnh vực này và có nhiều thuật
tốn nổi tiếng đã được phát minh như: Thuật toán Bellman – Ford, thuật toán
Dijkstra, thuật toán Floyd, thuật toán Johnson…
Tuy nhiên việc nghiên cứu cải tiến nâng cao hiệu quả của các thuật tốn
tìm đường đi tối ưu luôn nhận được sự quan tâm của nhiều người, nhiều tổ
chức, cơ quan. Vì lý do nói trên và được sự gợi ý của PGS – TS Đoàn Văn
Ban, tác giả đã chọn đề tài này để nghiên cứu trong luận văn tốt nghiệp thạc sĩ
của mình.
 Phạm vi nghiên cứu của đề tài
Các khái niệm cơ bản về đồ thị, các thuật tốn tìm đường đi tối ưu trên
đồ thị, cấu trúc dữ liệu Fibonacci heap, ứng dụng cấu trúc dữ liệu này vào
việc cải tiến nâng cao hiệu quả của thuật tốn tìm đường đi tối ưu trên đồ thị.
Số hóa bởi Trung tâm Học liệu – ĐHTN




2

Ứng dụng các thuật tốn tìm đường đi tối ưu trên đồ thị đã nghiên cứu để giải
quyết một số bài tốn tìm đường đi tối ưu trong mạng giao thông.

 Hướng nghiên cứu của đề tài
- Nghiên cứu thuật tốn Dijkstra tìm đường đi tối ưu trên đồ thị, nghiên
cứu về Fibonacci heap và ứng dụng cấu trúc dữ liệu này để cải tiến thuật toán
Dijkstra.
- Nghiên cứu về thuật toán tối ưu đàn kiến, ứng dụng thuật toán này để
giải quyết bài tốn tìm đường đi tối ưu trên đồ thị.
- Ứng dụng hai thuật toán trên giải quyết một số bài tốn tìm đường đi
tối ưu trên mạng giao thơng.
 Đề tài gồm có 3 chương:
Chương 1: Trình bày một số khái niệm cơ bản về đồ thị, một số dạng
bài tốn tìm đường đi tối ưu trên đồ thị, phần chủ yếu của chương này là trình
bày về Fibonacci heap và dùng cấu trúc dữ liệu này để cải tiến nâng cao hiệu
quả thuật toán Dijkstra.
Chương 2: Trình bày về thuật tốn tối ưu đàn kiến và thuật tốn ACO
giải bài tốn tìm đường đi tối ưu. Thuật toán đàn kiến là một thuật toán tương
đối mới và khả năng ứng dụng thực tế cao.
Chương 3: Ứng dụng thuật toán Dijkstra đã cải tiến và thuật tốn đàn
kiến vào việc giải một số bài tốn tìm đường đi tối ưu trên mạng giao thông.
 Ý nghĩa khoa học của đề tài:
- Thuật toán Dijkstra Fibonacci heap là thuật tốn mạnh, nó có thể được
ứng dụng để giải quyết các bài toán cả trong nghiên cứu lý thuyết và trong
thực tiễn. Hiện tại thuật toán này chưa phổ biến ở Việt Nam, vì thế đề tài này
có thể sẽ có ích cho những người quan tâm đến lĩnh vực này. Đề tài cũng có
Số hóa bởi Trung tâm Học liệu – ĐHTN




3


thể giúp cho các em học sinh Chuyên Tin có thêm một công cụ mạnh để giải
quyết một số bài tốn có liên quan trong lập trình.
- Thuật tốn ACO là thuật tốn gần đúng, tuy nhiên nó rất hiệu quả
trong việc giải quyết các bài toán thực tiễn . Đề tài đã ứng dụng thành cơng
hai thuật tốn nói trên vào việc giải quyết một số bài toán mà thực tiễn đang
đặt ra.

Số hóa bởi Trung tâm Học liệu – ĐHTN




4

CHƯƠNG 1
CÁC THUẬT TỐN TÌM ĐƯỜNG ĐI TỐI ƯU TRÊN ĐỒ THỊ

1.1. Các khái niệm cơ bản của lý thuyết đồ thị
1.1.1. Định nghĩa đồ thị
Đồ thị là một cấu trúc rời rạc bao gồm các đỉnh và các cạnh nối các
đỉnh này. Chúng ta phân biệt các loại đồ thị khác nhau bởi kiểu và số lượng
cạnh nối hai đỉnh nào đó của đồ thị.
Định nghĩa 1.1. Đơn đồ thị vô hướng G = (V,E) bao gồm V là tập các
đỉnh, và E là tập các cặp khơng có thứ tự gồm hai phần tử khác nhau của V
gọi là các cạnh [3].
Định nghĩa 1.2. Đa đồ thị vô hướng G = (V,E) bao gồm V là tập các
đỉnh, và E là họ các cặp khơng có thứ tự gồm hai phần tử khác nhau của V
gọi là các cạnh. Hai cạnh e1 và e2 được gọi là cạnh lặp nếu chúng cùng
tương ứng với một cặp đỉnh [3].
Định nghĩa 1.3. Đơn đồ thị có hướng G = (V,E) bao gồm V là tập các

đỉnh, và E là tập các cặp có thứ tự gồm hai phần tử khác nhau của V gọi là
các cung [3].
Định nghĩa 1.4. Đa đồ thị có hướng G = (V,E) bao gồm V là tập các
đỉnh, và E là họ các cặp có thứ tự gồm hai phần tử khác nhau của V gọi là
các cung. Hai cung e1 và e2 được gọi là cung lặp nếu chúng cùng tương ứng
với một cặp đỉnh [3].

Số hóa bởi Trung tâm Học liệu – ĐHTN




5

c

2
3

a

1

d
4
b

6

e


5
a)

b)

Hình 1.1. Hai loại đồ thị cơ bản:
a) Đồ thị vơ hướng (6 đỉnh, 9 cạnh). b) Đồ thị có hướng (5 đỉnh, 7 cung).

1.1.2. Các thuật ngữ cơ bản
Định nghĩa 1.5. Hai đỉnh u và v của đồ thị vô hướng G được gọi là kề
nhau nếu (u,v) là cạnh của đồ thị G. Nếu e = (u,v) là cạnh của đồ thị thì
chúng ta nói cạnh này là liên thuộc với hai đỉnh u và v, hoặc cũng nói là cạnh
e là nối đỉnh u và đỉnh v, đồng thời các đỉnh u và v sẽ được gọi là các đỉnh
đầu của cạnh (u,v) [3].
Để có thể biết được bao nhiêu cạnh liên thuộc với một đỉnh, chúng ta
đưa vào định nghĩa sau:
Định nghĩa 1.6. Gọi bậc của đỉnh v trong đồ thị vô hướng là số cạnh
liên thuộc với nó và sẽ kí hiệu là deg(v).
Định lý 1.1. Giả sử G = (V, E) là đồ thị vơ hướng với m cạnh. Khi đó

2m   deg(v) [3].
vV

Hệ quả 1.1. Trong đồ thị vô hướng, số đỉnh bậc lẻ (nghĩa là có bậc là
số lẻ) là một số chẵn [3].
Định nghĩa 1.7. Nếu e = (u,v) là cung của đồ thị có hướng G thì chúng
ta nói hai đỉnh u và v là kề nhau, và nói cung (u,v) nối đỉnh u và đỉnh v hoặc
Số hóa bởi Trung tâm Học liệu – ĐHTN





6

cũng nói cung này là đi ra khỏi đỉnh u và đi vào đỉnh v. Đỉnh u(v) sẽ được gọi
là đỉnh đầu (cuối) của cung (u,v) [3].
Định nghĩa 1.8. Chúng ta gọi bán bậc ra (bán bậc vào) của đỉnh v
trong đồ thị có hướng là số cung của đồ thị đi ra khỏi nó (đi vào nó) và ký
hiệu là: deg+(v) (deg-(v)) [3].
Định lý 1.2. Giả sử G= (V, A) là đồ thị có hướng. Khi đó

 deg
vV



(v)   (deg  (v))  A [3].
vV

1.1.3. Đường đi, chu trình, đồ thị liên thơng
Định nghĩa 1.9. Đường đi độ dài n từ đỉnh u đến đỉnh v, trong đó n là
số nguyên dương, trên đồ thị vô hướng G = (V, E) là dãy x0, x1,.., xn-1, xn trong
đó u = x0 , v = xn, (xi, xi+1)  E, i = 0, 1, 2,…, n-1. Đường đi nói trên cịn có
thể biểu diễn dưới dạng dãy các cạnh: (x0, x1), (x1, x2), .. , (xn-1, xn).
Đỉnh u gọi là đỉnh đầu, còn đỉnh v gọi là đỉnh cuối của đường đi.
Đường đi có đỉnh đầu trùng với đỉnh cuối (tức là u = v) được gọi là chu trình.
Đường đi hay chu trình được gọi là đơn nếu như khơng có cạnh nào bị lặp lại
[3].
Định nghĩa 1.10. Đường đi độ dài n từ đỉnh u đến đỉnh v, trong đó n là

số nguyên dương, trên đồ thị có hướng G = (V, A) là dãy x0, x1,.., xn-1, xn trong
đó u = x0, v = xn , (xi , xi+1)  A, i = 0, 1, 2 , .. , n-1. Đường đi nói trên cịn
có thể biểu diễn dưới dạng dãy các cung: (x0, x1), (x1, x2), .., (xn-1, xn).
Đỉnh u gọi là đỉnh đầu, còn đỉnh v gọi là đỉnh cuối của đường đi. Đường
đi có đỉnh đầu trùng với đỉnh cuối (tức là u = v) được gọi là chu trình. Đường đi
hay chu trình được gọi là đơn nếu như khơng có cung nào bị lặp lại [3].
Định nghĩa 1.11. Đồ thị vô hướng G = (V, E) được gọi là liên thông
nếu ln tìm được đường đi giữa hai đỉnh bất kì của nó.
Số hóa bởi Trung tâm Học liệu – ĐHTN




7

Định nghĩa 1.12. Chúng ta gọi đồ thị con của đồ thị G = (V, E) là đồ
thị H = (W, F), trong đó W  V và F  E.
Trong trường hợp đồ thị là khơng liên thơng, nó sẽ rã ra thành một số
đồ thị con liên thông đơi một khơng có đỉnh chung. Những đồ thị con liên
thông như vậy chúng ta sẽ gọi là các thành phần liên thông của đồ thị [3] .

1.1.4. Đồ thị có trọng số
Đồ thị được sử dụng để giải các bài toán trong nhiều lĩnh vực khác
nhau. Chẳng hạn, đồ thị được sử dụng để xác định các mạch vòng trong vấn
đề giải tích mạch điện. Chúng ta có thể xác định xem hai máy tính trong mạng
có thể trao đổi thơng tin với nhau được hay khơng. Khi đó, đồ thị được sử
dụng để biễu diễn mạng truyền thông với các đỉnh là các nút mạng, các cạnh,
các cung là các đường truyền dữ liệu giữa các nút mạng. Đồ thị có thể dùng
để biễu diễn các đường đi trong một vùng: Các đỉnh tương ứng với các ngã 3,
ngã 4, còn các cạnh, các cung tương ứng là các đường đi 2 chiều và đường đi

1 chiều. Để cấu trúc đồ thị có thể biễu diễn được các bài toán thực tế người ta
đưa vào khái niệm đồ thị có trọng số, trên mỗi cạnh hay mỗi cung được gán
một trọng số thể hiện chi phí cho việc thực hiện một mục đích nào đó trên
cạnh hay trên cung đó.
Định nghĩa 1.13. Đồ thị có trọng số là bộ 3 G = (V, E, w), trong đó w
là hàm trọng số:
w:E -> R, R: tập số thực, ngoài ra cịn có thể kí hiệu w bằng c hoặc
weight, cost.
Cho S là một tập con của E  A, khi đó chúng ta kí hiệu w(S) = ∑w(s)|
s  S là giá trị trọng số của tập S.

Số hóa bởi Trung tâm Học liệu – ĐHTN




8

1.2. Cây
Định nghĩa 1.14: Ta gọi cây là một đồ thị vơ hướng liên thơng khơng
có chu trình. Đồ thị khơng có chu trình gọi là rừng.
Ví dụ: Trong hình 3 là một rừng gồm 3 cây T1, T2, T3.

T1

T2

T3
Hình 1.2. Rừng gồm 3 cây T1, T2, T3


Có thể nói rằng cây là một cấu trúc đồ thị vô hướng đơn giản nhất.
Định lý 1.3 sau đây nêu lên một số tính chất của cây.
Định lý 1.3: Giả sử G = (V, E) là đồ thị vô hướng n đỉnh, khi đó các
mệnh đề sau đây là tương đương:
(1) G là cây.
(2) G khơng chứa chu trình và có n-1 cạnh.
(3) G liên thơng và có n-1 cạnh.
(4) G liên thơng và mỗi cạnh của nó đều là cầu.
(5) Hai đỉnh bất kỳ của G được nối với nhau bởi đúng một đường
đi đơn.
(6) G khơng chứa chu trình nhưng nếu cứ thêm vào nó một cạnh ta thu
được đúng một chu trình [3].

1.3. Bài tốn đường đi tối ưu trên đồ thị
Như đã nói ở phần mở đầu, bài tốn tìm đường đi tối ưu trên đồ thị có
một ý nghĩa thực tế vô cùng to lớn. Trong chương một này chỉ tập trung
Số hóa bởi Trung tâm Học liệu – ĐHTN




9

nghiên cứu đường đi tối ưu trên đồ thị có hướng G = (V, E), |V|=n, |E|= m với
mỗi cung được gán một trọng số, nghĩa là mỗi cung (u,v) E được đặt tương
ứng với một số thực a(u,v) gọi là trọng số của nó. Trong ứng dụng cụ thể cho
từng bài tốn thì trọng số của một cung có thể là độ dài cung (u,v), có thể là
chi phí đi từ u đến v cũng có thể là thời gian đi từ u đến v... Nếu (u, v) E ta
sẽ đặt a(u, v) = . Nếu dãy v0, v1 , .. , vp là một đường đi trên G thì độ dài của
nó được định nghĩa là


p

 a(v
i 1

i 1

,vi ) , nghĩa là độ dài của một đường đi chính là

tổng các trọng số của các cung trên đường đi đó. Với đồ thị vơ hướng ta hồn
tồn có thể chuyển thành đồ thị có hướng bằng cách thay mỗi cạnh (u, v) bằng
hai cung (u, v) và cung (v, u) có cùng trọng số là trọng số của cạnh (u, v).
Bài tốn tìm đường đi tối ưu trên đồ thị có thể phát biểu dạng tổng
quát như sau: Tìm đường đi có độ dài nhỏ nhất xuất phát từ đỉnh s  V (s là
đỉnh xuất phát) đến đỉnh t  V (t là đỉnh đích).
Đường đi như vậy ta gọi là đường đi tối ưu từ đỉnh s đến đỉnh t, độ dài
của đường đi này ta gọi là khoảng cách từ s đến t và ký hiệu là d(s, t). Nếu
không tồn tại đường đi từ s đến t ta đặt d(s, t) = . Trong một số trường hợp
đường đi tối ưu từ s đến t còn bị ràng buộc thêm một số điều kiện khác nữa, ví
dụ phải đi qua một số đỉnh cố định cho trước hoặc phải quay lại đỉnh xuất
phát ...
Dễ thấy rằng nếu trong G không tồn tại chu trình có độ dài âm (gọi tắt
là chu trình âm) thì đường đi tối ưu từ s đến t khơng có đỉnh nào bị lặp lại.
Đường đi khơng có đỉnh lặp lại gọi là đường đi cơ bản hoặc đường đi đơn.
Trong trường hợp trong G có chu trình âm thì khoảng cách giữa hai điểm s và
t có thể khơng xác định, bởi vì bằng cách đi vịng theo chu trình âm một số
lần đủ lớn nào đó thì d(s,t) có thể nhỏ hơn bất kỳ một số thực nào đó cho
trước [3]. Khi đó ta có thể đặt vấn đề tìm đường đi cơ bản tối ưu, tuy nhiên
Số hóa bởi Trung tâm Học liệu – ĐHTN





10

bài tốn sẽ rất phức tạp, vì vậy trong luận văn này chúng ta sẽ giả thiết trong
G các cung đều có trọng số khơng âm. Trường hợp trong đồ thị G trọng số các
cung khơng âm, có nhiều thuật tốn tìm đường đi tối ưu nổi tiếng như thuật
tốn For_Bellman, thuật tốn Dijkstra, thuật tốn Floyd... Trong phần cịn lại
của chương này của luận văn chúng ta sẽ nghiên cứu về thuật toán Dijkstra và
sử dụng Fibonacci heap để cải tiến thuật toán Dijkstra.

1.4. Thuật toán Dijkstra
1.4.1. Phát biểu bài tốn
“Cho đồ thị có hướng có trọng số G = (V, E), hãy tìm một đường đi tối
ưu xuất phát từ đỉnh s thuộc V, đến một đỉnh t cũng thuộc V.”
Bài tốn có thể được tìm thấy rất nhiều trong thực tế, chẳng hạn trong
mạng lưới giao thông đường bộ, đường thủy, đường không, trong truyền tải
dữ liệu của một mạng máy tính.

1.4.2.Mơ tả thuật tốn
Trong trường hợp trọng số trên cung khơng âm, bài tốn trên có thể giải
quyết hiệu quả bằng thuật tốn Dijkstra mơ tả như sau [3] :
Bước 1: Khởi tạo
Mỗi đỉnh v thuộc V, gọi d[v] là khoảng cách từ s đến v. Ban đầu
d[s]:=0, d[v≠s] := ∞, ban đầu các đỉnh được coi là chưa cố định (mỗi đỉnh có
một trong 2 trạng thái là tự do hoặc cố định, tự do nghĩa là d[v] cịn có thể tối
ưu hơn nữa, cố định tức là d[v] đã bằng độ dài đường đi tối ưu từ s đến t,
không tối ưu được nữa).

Bước 2: Lặp cho đến khi t trở thành đỉnh cố định
Bước lặp bao gồm 2 thao tác :
Thao tác 1: Cố định nhãn
Số hóa bởi Trung tâm Học liệu – ĐHTN




11

Chọn đỉnh u tự do có nhãn d[u] nhỏ nhất và cố định nhãn cho nó.
Thao tác 2: Sửa nhãn
Đối với mỗi đỉnh v tự do, kề với u. Nếu d[v] > d[u]+c[u,v] thì ta sẽ
sửa nhãn cho v: d[v] := d[u]+c[u,v] và lưu u là đỉnh kề trước v trên đường đi
tối ưu (c[u,v] là trọng số của cung (u, v))
Bước 3: Xuất kết quả
Trả lại d[t] là độ dài đường đi tối ưu, kết hợp truy vết để tìm đường đi.
Mơ hình :
Repeat
u := FindMin();
if u = t then exit ;
Đánh dấu u đã cố định;
Repair(u); // tiến hành sửa nhãn cho các đỉnh kề u
Until False; [3]

Độ phức tạp của FindMin() là O(n), của Repair(u) là O(n). Số lần lặp
của bước 2 sẽ là số cung trong đường đi tối ưu, tức là khoảng O(n). Thuật
toán Dijkstra cài đặt như trên sẽ có độ phức tạp O(n2), kết quả này là khơng
khả thi cho đồ thị có số đỉnh n lớn.


1.5. Thuật toán Dijkstra kết hợp với Fibonacci heap
Do độ phức tạp của thuật toán Dijkstra là O(n2) nên khi số đỉnh của đồ
thị lớn, chương trình chạy rất chậm, trong phần 1.5 này chúng ta sẽ sử dụng
Fibonacci heap để cải tiến thuật toán này.

1.5.1. Hàng đợi ưu tiên
1.5.1.1. Khái niệm hàng đợi, hàng đợi ưu tiên
Hàng đợi (queue): Là một kiểu danh sách mà việc bổ sung một phần tử
được thực hiện ở cuối danh sách còn việc loại bỏ một phần tử được thực hiện
ở đầu danh sách. Có thể hình dung hàng đợi như một hàng người xếp hàng
Số hóa bởi Trung tâm Học liệu – ĐHTN




12

mua vé: Người xếp hàng trước sẽ được mua vé trước, người đứng đầu tiên
mua vé xong đi ra thì người thứ hai tiến lên thay vị trí người đứng đầu, cịn
người mới đến sẽ đứng vào cuối hàng. Vì nguyên tắc vào trước ra trước nên
hàng đợi còn được gọi là danh sách kiểu FIFO (First in first out). Có 6 thao
tác cơ bản đối với hàng đợi [2]:
Init: Tạo một ngăn xếp rỗng.
isEmpty: Cho biết hàng đợi có rỗng hay khơng.
isFull: Cho biết hàng đợi có đầy khơng.
Get: Đọc giá trị của phần tử ở đầu hàng đợi.
Push: Đẩy (bổ sung) một phần tử vào hàng đợi.
Pop: Lấy một phần tử ra khỏi hàng đợi.
Ta có thể biểu diễn hàng đợi bằng mảng hoặc dang sách móc nối [2].
Hàng đợi ưu tiên: Hàng đợi có độ ưu tiên, gọi tắt là hàng đợi ưu tiên

(priority queue) là một cấu trúc dữ liệu quan trọng dùng trong việc cài đặt
nhiều thuật toán. Hàng đợi ưu tiên là một kiểu danh sách chứa các phần tử của
một tập hữu hạn S nào đó, mỗi phần tử của S được gán cho một mức độ ưu
tiên nào đó. Ta đánh số các phần tử của S lần lượt từ 1 đến n và đồng nhất
mỗi phần tử với chỉ số của nó, khi đó độ ưu tiên của phần tử i là một số thực
p[i] ( i = 1, 2, .., n).
Với một hàng đợi ưu tiên có các thao tác chính sau đây [2]:
+ Insert(i): Đẩy phần tử i vào hàng đợi ưu tiên nếu nó chưa có trong
hàng đợi.
+ Find min(Find max): Trả về phần tử có độ ưu tiên nhỏ nhất (lớn nhất)
trong hàng đợi ưu tiên.
+ Extract: Trả về phần tử có độ ưu tiên nhỏ nhất (lớn nhất) trong hàng
Số hóa bởi Trung tâm Học liệu – ĐHTN




13

đợi ưu tiên, và loại bỏ nó khỏi hàng đợi ưu tiên.
+ Update(i, new(p)): Cập nhật độ ưu tiên của phần tử i thành new(p).
Hàng đợi ưu tiên là một biến thể của hàng đợi, nó khác ở chỗ là hàng
đợi thông thường hoạt động theo kiểu vào trước ra trước cịn trong hàng đợi
ưu tiên thủ tục Extract ln lấy ra phần tử có độ ưu tiên nhỏ nhất (lớn nhất).

1.5.1.2. Cấu trúc dữ liệu heap
Ta có thể dùng mảng hoặc danh sách móc nối để biểu diễn một hàng
đợi ưu tiên, khi đó các thao tác Insert và Update có thể thực hiện với độ phức
tạp là O(1), tuy nhiên các thao tác Find min (Find max) và Extract lại có độ
phức tạp là O(n). Vì vậy, trong thực tế người ta hay dùng cấu trúc dữ liệu trừu

tượng heap (đống) để biểu diễn hàng đợi ưu tiên.
Heap là một cấu trúc dữ liệu trừu tượng, bao gồm một tập n phần tử,
mỗi phần tử có một giá trị khóa xác định. Các phép tốn trên một heap được
mô tả trong bảng dưới đây :
Make_ heap

Trả về một heap mới rỗng.

Insert (x,h)

Chèn một giá phần tử x mới,có khóa xác định vào heap

Find_ min

Trả về phần tử có khóa nhỏ nhất, khơng làm thay đổi heap

Extract_ min

Trả về phần tử có khóa nhỏ nhất và xóa nó ra khỏi heap

Trong một số bài tốn cịn có thêm các phép toán sau :
Union(h1,h2)

Hợp nhất hai heap h1, h2 thành heap mới, đồng thời xóa h1,
h2

Decrease(∆,x,h) Giảm khóa của phần tử x một lượng ∆ trong heap
Delete(xh)

Xóa phần tử X ra khỏi heap


Số hóa bởi Trung tâm Học liệu – ĐHTN




14

Heap cịn có thể gọi là hàng đợi có độ ưu tiên (priority queue) hay các
đống khả trộn (mergeable heaps).
Một số loại heaps, và thời gian thao tác các phép tốn được trình bày
trong bảng dưới đây [6]:
Heaps
Linked

Thao tác

list

Binary

Bionimal

Fibonacci Relax

make heap

O(1)

O(1)


O(1)

O(1)

O(1)

Insert (x,h)

O(1)

O(logN)

O(logN)

O(1)

O(1)

find min

O(N)

O(1)

O(logN)

O(1)

O(1)


extract min

O(N)

O(logN)

O(logN)

O(logN)

O(logN)

Union(h1,h2)

O(1)

O(N)

O(logN)

O(1)

O(1)

Decrease(∆,x,h) O(1)

O(logN)

O(logN)


O(1)

O(1)

Delete(x,h)

O(logN)

O(logN)

O(logN)

O(logN)

O(N)

Trong phần tiếp theo chúng ta sẽ nghiên cứu kỹ về Fibonacci heap.

1.5.2. Fibonacci heap
1.5.2.1. Giới thiệu Fibonacci heap (Đống Fibonacci)
Cấu trúc dữ liệu Fibonacci heap (Đống Fibonacci) được hai giáo sư
Fredman và Tarjan đưa ra vào năm 1986, nhằm áp dụng vào các bài toán tối
ưu trên đồ thị, độ phức tạp của các thuật tốn giải một số bài tốn điển hình
khi sử dụng Fibonacci heap được thống kê dưới đây [6]:
O(nlogn + m): Cho bài tốn tìm đường đi tối ưu xuất phát từ một đỉnh.
O(n2logn + nm): Cho bài tốn tìm đường đi tối ưu giữa mọi cặp đỉnh.
O(n2logn + nm): Cho bài tốn so khớp hai nhánh có trọng số .
Số hóa bởi Trung tâm Học liệu – ĐHTN





15

Trước khi định nghĩa Fibonacci heap, ta đưa ra một số khái niệm:
Cây có gốc: Là một cây tự do mà ở đó có một trong các đỉnh được phân
biệt với các đỉnh còn lại và được gọi là gốc.
Cây có thứ tự: Là cây có gốc, mà các nút con trực thuộc một nút cha
được sắp xếp theo một thứ tự xác định.
Cây sắp xếp theo đống: Là cây có gốc, và nếu nút x là nút bất kỳ thì nó
có giá trị khóa lớn hơn hoặc bằng (nhỏ hơn hoặc bằng) khóa của cha nó. Từ
đó nút gốc là nút có khóa nhỏ nhất (lớn nhất).
Định nghĩa : Fibonacci heap là một tập hợp các cây được sắp xếp theo
đống. Các cây trong Fibonacci heap không bị ràng buộc về thứ tự[6].

Hình1.3: Fibonacci heap gồm 5 cây sắp xếp theo đống với 14 nút [4]

1.5.2.2. Cấu trúc Fibonacci heap
Hình 1.4 mơ tả cách biểu diễn cấu trúc heap. Mỗi nút x chứa một biến
trỏ p[x] trỏ đến cha của nó và một biến trỏ child[x] trỏ đến một con bất kỳ của
nó. Các con của x được nối kết theo một danh sách nối kết đơi theo vịng tròn
mà ta gọi là danh sách con của x. Mỗi nút y trong danh sách con có các biến
trỏ left[y] và right[y] trỏ đến anh em ruột trái và phải của nó. Nếu nút y là duy
nhất thì left[y] = right[y] = y. Thứ tự xuất hiện các nút trong danh sách con là
tùy ý.
Việc thể hiện danh sách con bằng danh sách nối đơi vịng trịn có 2 ưu
Số hóa bởi Trung tâm Học liệu – ĐHTN





16

điểm: Thứ nhất, có thể gỡ bỏ một nút ra khỏi danh sách với độ phức tạp là
O(1). Thứ hai, có thể ghép nối 2 danh sách với độ phức tạp tính tốn là O(1).
Ngồi ra mỗi nút x cịn có :
degree[x]: Lưu số nút trong danh sách con của x.
bool mark[x]: Kiểm tra x đã mất một con hay chưa kể từ lần cuối cùng
x trở thành con của một nút khác.
Các gốc của tất cả các cây trong Fibonacci heap được nối kết với nhau
bằng các biến trỏ left, right của chúng tạo thành một danh sách nối kết đơi
vịng trịn gọi là danh sách gốc. Biến trỏ min[H] trỏ đến nút có khóa nhỏ nhất
trong danh sách gốc, từ đây ta sẽ coi min[H] là đại diện của H nói cách khác
là minH quản lý H. Số lượng các nút trong H sẽ được lưu trong biến nH.

Hình 1.4. Mơ phỏng cấu trúc Fibonacci heap [4]
Cấu trúc dữ liệu miêu tả một nút trong Fibonacci heap[4]:
node = record
key : integer;
degree : integer;
parent : ^node;
child : ^node;
left : ^node;
right : ^node ;
mark : boolean;
end;
Số hóa bởi Trung tâm Học liệu – ĐHTN





17

Hàm tiềm năng
Để phân tích đánh giá độ phức tạp trong các phép toán đối với
Fibonacci heap ta sử dụng phương pháp phân tích tiềm năng, khi đó hao phí
khấu trừ của một thuật toán được xem là độ phức tạp của thuật tốn đó [4].
Đối với Fibonacci heap, ta sử dụng hàm tiềm năng Φ(H) = t(H) + 2m(H),
trong đó: t(H) là số lượng nút trong danh sách gốc, m(H) là số lượng các nút
đánh dấu. Ta mặc nhận rằng ở trạng thái ban đầu Φ(H) = 0.
Ở ví dụ trên : Φ(H) = 5 + 2  3 = 11.

1.5.2.3. Các thao tác trên Fibonacci heap
Ý tưởng chính trong các thao tác trên Fibonacci heap đó là trì hỗn các
cơng việc chưa cần thiết nếu có thể, chờ đến lúc buộc phải thực hiện thì thực
hiện cùng một lúc nhiều cơng việc, điều đó giúp giảm bớt các phép tính tốn.
Nếu số lượng các cây trong một Fibonacci heap khơng lớn, ta có thể nhanh
chóng xác định nút cực tiểu mới bằng thủ tục EXTRACT_ MIN. Ta sẽ không
gắng thống nhất các cây trong Fibonacci heap khi chèn một nút mới hoặc hợp
nhất hai đống. Việc thống nhất các cây trong đống chỉ phải làm khi gặp thủ
tục EXTRACT_MIN, là thủ tục tìm nút cực tiểu và xóa nó khỏi đống.
(1) Tạo một Fibonacci heap mới
Để tạo một Fibonacci heap rỗng ta dùng thủ tục FIB_HEAP_ MAKE,
thủ tục này phân bổ và trả về đối tượng Fibonacci heap, trong đó n[H] = 0,
min[H] = NIL, ngay sau lời gọi thủ tục này thì chưa có cây nào trong H.
Vì thế t(H) = 0, m(H) = 0, nên Φ(H) = 0. Như vậy, mức hao phí khấu
trừ (độ phức tạp tính tốn) của FIB_HEAP_MAKE bằng với mức hao phí thực
tế O(1) của nó.
(2) Chèn một nút mới

Thủ tục dưới đây chèn nút x với khóa là key[x] vào Fibonacci heap H
được quản lý bởi biến con trỏ min[H]:

Số hóa bởi Trung tâm Học liệu – ĐHTN




18

Procedure FIB_HEAP_INSERT (var x, min[H] : tro); [4]
// tro là một kiểu con trỏ, trỏ vào các node: tro = ^node;
begin
1. degree[x] := 0;
2. p[x] := NIL;
3. child[x] := NIL;
4. left[x] := x;
5. right[x] := x;
6. mark[x] := false;
7. ghép nối danh sách gốc chứa x với danh sách gốc H;
8. if min[H] = NIL hoặc x^.key < minH^.key
9. then minH := x;
10. n[H] = n[H]+1;
end;

Các lệnh từ dòng 1- 6, khởi tạo cấu trúc của nút x, khiến nó trở thành
danh sách nối đơi theo vịng trịn, dịng 7 bổ sung nút x vào danh sách gốc của
H. Như vậy nút x trở thành một cây nút đơn được sắp xếp theo đống trong
Fibonacci heap. Nó khơng có cây con và khơng được đánh dấu. Các dịng 8 9 cập nhật min[H]. Dòng 10 tăng số lượng nút trong H.
Có thể nhận ra rằng FIB_HEAP_INSERT(c,min[H]) sẽ khơng gắng

thống nhất các cây trong đống. Nếu k phép toán FIB_HEAP_INSERT thực
hiện thì sẽ có k cây mới được bổ sung vào danh sách gốc.

Hình 1.5: Minh họa chèn thêm nút có key 21 vào Fibonacci heap[4]
Số hóa bởi Trung tâm Học liệu – ĐHTN




19

Để xác định mức hao phí khấu trừ của FIB_HEAP_INSERT, gọi H là
Fibonacci heap ban đầu và H’ là Fibonacci heap kết quả, thì t(H’) = t(H)+1,
m(H’) = m(H), sự gia tăng trong hàm tiềm năng là : Φ(H’) - Φ(H) = 1 Bởi
mức hao phí thực tế là O(1), nên mức hao phí khấu trừ là O(1) + 1 = O(1).
Mã nguồn thao tác FIB_HEAP_INSERT:
procedure FIB_HEAP_INSERT(var x, minH: tro); [4]
begin
degree[x] := 0;
p[x] := NIL;
child[x] := NIL;
left[x] := x;
right[x] := x;
mark[x] := false;
if minH <> nil // bắt đầu ghép nối danh sách gốc chứa x với danh sách gốc H;
then

begin
x^.left := minH.left;
minH^.left^.right := x;

x^.right := minH;
minH^.left := x;
if minH^.key > x^.key
then minH := x;
end

else minH := x; // kết thúc ghép nối danh sách gốc chứa x với danh sách gốc H;
n[H] = n[H]+1;
end;

Ở đây nút mới x đã được chèn vào bên trái minH, thực tế trong lập trình
ta có thể chèn x vào bên phải minH thì kết quả vẫn giống nhau.
(3) Tìm nút cực tiểu
Nút cực tiểu của Fibonacci heap được trỏ bởi min[H], do đó ta có thể
tìm nút cực tiểu với độ phức tạp tính tốn thực tế (hao phí thực tế) là O(1). Do
Số hóa bởi Trung tâm Học liệu – ĐHTN




20

tiềm năng của H không thay đổi, nên mức hao phí khấu trừ của phép tốn này
bằng với mức hao phí thực tế của nó là O(1).
(4) Hợp nhất hai Fibonacci heap [6]
Thủ tục dưới đây hợp nhất 2 Fibonacci heap H1 và H2 thành H, đồng
thời hủy H1, H2.
procedure FIB_HEAP_UNION(var min[H1], min[H2], minH : tro);
begin
1. n[H] := 0;

2. min[H] := min[H1];
3. ghép nối danh sách gốc của H2 với danh sách gốc của H;
4. if (min[H1] = NIL) hoặc (min[H2]^.key < min[H1]^.key) then
5. min[H] := min[H2];
6. n[H] := n[H1] + n[H2];
7. giải phóng các đối tượng H1 và H2;
end;

Các dòng 1-3 ghép nối các danh sách gốc của H1 và H2 thành một danh
sách gốc mới H. Các dòng 2, 4, 5 ấn định nút cực tiểu của H, dịng 6 cập nhật
lại số nút của H. Ta có thể thấy trong thủ tục FIB-HEAP-UNION(H1, H2)
không cần thực hiện thống nhất cây.
Sự thay đổi tiềm năng : Φ(H) – (Φ(H1) + Φ(H2)) = 0. Do đó mức hao
phí khấu trừ của FIB_HEAP_UNION bằng với mức hao phí thực tế O(1).
(5) Trích nút cực tiểu[4]
Đây là thủ tục phức tạp nhất của Fibonacci heap. Thủ tục này thực hiện
xóa nút cực tiểu ra khỏi H, đồng thời thực hiện việc thống nhất các cây đã bị
trì hỗn ở các phép tốn khác.
Số hóa bởi Trung tâm Học liệu – ĐHTN




×