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

Lập trình mô phỏng một số thuật toán trên đồ thị

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 (1.74 MB, 53 trang )

BỘ GIÁO DỤC VÀ ĐÀO TẠO
TRƢỜNG ĐẠI HỌC SƢ PHẠM HÀ NỘI 2






NGUYỄN THỊ CHIỀU



LẬP TRÌNH MÔ PHỎNG
MỘT SỐ THUẬT TOÁN TRÊN ĐỒ THỊ

Chuyên ngành: Khoa học máy tính
Mã số: 60 48 01 01


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


Ngƣời hƣớng dẫn khoa học: TS. Trần Minh Tƣớc









Hà Nội, 2014

LỜI CẢM ƠN

Nhân dịp hoàn thành khóa luận, tôi xin bày tỏ lòng biết ơn sâu sắc của
mình tới TS. Trần Minh Tƣớc đã tận tình giúp đỡ tôi trong quá trình hoàn
thành khóa luận này.
Tôi xin chân thành cảm ơn Ban giám hiệu, phòng Sau đại học, trƣờng
Đại học Sƣ phạm Hà Nội 2 cũng nhƣ toàn thể các thầy cô giáo trong trƣờng
đã tạo điều kiện thuận lợi trong quá trình tôi học tập và nghiên cứu.
Trong quá trình thực hiện công tác nghiên cứu không tránh khỏi những
hạn chế và thiếu sót, tôi xin chân thành cảm ơn những ý kiến đóng góp của
các thầy giáo, cô giáo và các bạn học viên.

Hà Nội, tháng 12 năm 2014
Tác giả




Nguyễn Thị Chiều

2

LỜI CAM ĐOAN
Tôi xin cam đoan, kết quả luận văn hoàn toàn là kết quả của tự bản
thân tôi tìm hiểu, nghiên cứu dƣới sự hƣớng dẫn của TS. Trần Minh Tƣớc,
khóa luận tốt nghiệp “LẬP TRÌNH MÔ PHỎNG MỘT SỐ THUẬT
TOÁN TRÊN ĐỒ THỊ” đƣợc hoàn thành, không trùng với bất cứ khóa luận
nào khác.

Trong quá trình làm khóa luận, tôi đã kế thừa những thành tựu của các
nhà khoa học với sự trân trọng và biết ơn.

Hà Nội, tháng 12 năm 2014
Tác giả





Nguyễn Thị Chiều
3

MỤC LỤC

Trang
DANH MỤC CÁC HÌNH
5
MỞ ĐẦU
7
Chƣơng 1. KIẾN THỨC CHUẨN BỊ
10
1.1 Tổng quan về thuật toán và mô phỏng thuật toán
10
1.1.1 Tổng quan về thuật toán
10
1.1.2 Mô phỏng thuật toán
11
1.2 Một số khái niệm cơ bản về đồ thị
13

1.2.1 Đồ thị
13
1.2.2 Biểu diễn đồ thị
15
1.3 Giới thiệu một số bài toán trên đồ thị
21
1.3.1 Bài toán tìm kiếm
21
1.3.2 Bài toán tìm luồng lớn nhất trong mạng vận tải
25
1.3.3 Bài toán tô màu đồ thị
33
Chƣơng 2. BIỂU DIỄN DỮ LIỆU VÀ THIẾT KẾ HỆ THỐNG
37
2.1 Biểu diễn dữ liệu
37
2.2 Phân tích và thiết kế hệ thống
37
2.2.1 Mục đích
37
2.2.2 Những yêu cầu thực tế
37
2.2.3 Đề xuất cho hệ thống mới
38
2.2.4 Thiết kế mô phỏng một số thuật toán trên đồ thị
38
2.3 Lựa chọn công cụ, ngôn ngữ lập trình
41
Chƣơng 3. CÀI ĐẶT CHƢƠNG TRÌNH
44

4

3.1 Hệ thống phân cấp mô-đun
44
3.2 Tạo giao diện ngƣời dùng
45
3.2.1 Mô phỏng thuật toán tìm kiếm DFS và BFS
46
3.2.2 Thuật toán tìm luồng cực đại Ford–Fulkerson
48
3.2.3 Thuật toán tô màu Welsh–Powell
48
3.3 Hƣớng dẫn sử dụng chƣơng trình
49
KẾT LUẬN
51
DANH MỤC CÁC TÀI LIỆU THAM KHẢO
52


5

DANH MỤC CÁC HÌNH
1.1 Biểu diễn đồ thị trên mặt phẳng
13
1.2 Biểu diễn đồ thị vô hƣớng
1
G
bằng ma trận vuông
16

1.3 Biểu diễn đồ thị có hƣớng
2
G
bằng ma trận vuông
16
1.4 Ví dụ đồ thị vô hƣớng 5 đỉnh
17
1.5 Đồ thị cài đặt trên mảng
18
1.6 Đồ thị cài đặt trên danh sách móc nối
18
1.7 Danh sách kề của mảng Adj gồm 12 phần tử
19
1.8 Danh sách móc nối của đồ thị
19
1.9 Đồ thị vô hƣớng 6 đỉnh, đỉnh xuất phát S=1
22
1.10 Minh họa ví dụ về thuật toán DFS dạng bảng
23
1.11 Minh họa ví dụ về thuật toán BFS dạng bảng
25
1.12 Tìm luồng cực đại trong mạng đỉnh phát S và đỉnh thu t
28
1.13 Mạng vận tải với lần lặp 1
28
1.14 Mạng vận tải với lần lặp 2
29
1.15 Mạng vận tải với lần lặp 3
30
1.16 Mạng vận tải với lần lặp 4

31
1.17 Mạng vận tải với lần lặp 5
32
1.18 Mạng vận tải sau khi kết thúc thuật toán
33
1.19 Đồ thị liên thông gồm 6 đỉnh chƣa tô màu
34
1.20 Đồ thị liên thông 6 đỉnh sau khi đã đƣợc tô màu
36
2.1 Quy trình phân tích và thiết kế các nhiệm vụ trƣớc khi mô phỏng
39
2.2 Mô-đun mô phỏng một số thuật toán trên đồ thị
39
6

2.3 Mô hình bài toán mô phỏng thuật toán
41
3.1 Mô-đun mô phỏng thuật toán DFS
44
3.2 Mô-đun mô phỏng thuật toán BFS
44
3.3 Mô-đun mô phỏng thuật toán Welsh–Powell
45
3.4 Giao diện chƣơng trình
45
3.5 Mô phỏng thuật toán BFS ở đồ thị có hƣớng liên thông
46
3.6 Mô phỏng thuật toán BFS ở đồ thị có hƣớng không liên thông
47
3.7 Mô phỏng thuật toán DFS ở đồ thị vô hƣớng liên thông

47
3.8 Mô phỏng thuật toán DFS ở đồ thị vô hƣớng không liên thông
47
3.9 Thuật toán Ford – Fulkerson với đỉnh nguồn 6, đỉnh đích 2
48
3.10 Thuật toán Welsh–Powell với đồ thị liên thông
49
3.11 Thuật toán Welsh–Powell với đồ thị không liên thông
49

7

MỞ ĐẦU
1. Lý do chọn đề tài
Những năm gần đây, ở Việt Nam môn Tin học đã đƣợc đƣa vào
chƣơng trình của học sinh trung học cơ sở và trung học phổ thông nhƣ là một
môn học chính thức. Đối với khối học sinh chuyên Tin học và học sinh giỏi
Tin học các vấn đề về đồ thị cũng đã đƣợc đề cập. Tuy nhiên, lý thuyết đồ thị
và các thuật toán trên đồ thị vẫn là một vấn đề rộng và phức tạp. Việc hiểu và
cài đặt tốt các thuật toán đó đòi hỏi thời gian và công sức rất lớn.
Nhƣ một phần của quá trình học thuật toán, việc mô phỏng các thuật
toán nhƣ một công cụ trợ giúp ngƣời học theo dõi chi tiết các bƣớc hoạt động
của thuật toán và các thay đổi của cấu trúc dữ liệu trong suốt quá trình thực
thi. Từ đó giúp ngƣời học tƣ duy thuật toán nhanh hơn và ngày càng yêu thích
giải thuật.
Với sự bùng nổ của công nghệ thông tin, thì việc mô phỏng thuật toán
ngày càng trở nên hữu ích và trở thành giáo cụ trực quan trong hầu hết các
lĩnh vực, nhất là trong môi trƣờng giáo dục nhƣ hiện nay.
Trong phạm vi của luận văn tốt nghiệp thạc sĩ chuyên ngành khoa học
máy tính, từ sự đề xuất hƣớng nghiên cứu và trực tiếp hƣớng dẫn của TS.

Trần Minh Tƣớc, chúng tôi xác định nhiệm vụ của đề tài là nghiên cứu về một
số thuật toán cơ bản trên đồ thị, sau đó sử dụng một ngôn ngữ lập trình để
triển khai xây dựng chƣơng trình nhằm mô phỏng hoạt động của một số thuật
toán trên đồ thị. Từ đó chúng tôi đặt tên luận văn là: “Lập trình mô phỏng
một số thuật toán trên đồ thị”. Nội dung luận văn đƣợc chia thành 3 chƣơng:
Chƣơng 1. Kiến thức chuẩn bị.
Ở chƣơng này chúng tôi trình bày tổng quan về thuật toán và mô phỏng
thuật toán, một số khái niệm cơ bản về đồ thị và giới thiệu một số bài toán
trên đồ thị.
8

Chƣơng 2. Biểu diễn dữ liệu và thiết kế hệ thống.
Chƣơng này, chúng tôi nói về cách biểu diễn dữ liệu của chƣơng
trình, quá trình phân tích, thiết kế và xây dựng hệ thống mô phỏng các thuật
toán trên.
Chƣơng 3. Cài đặt chƣơng trình.
Trong chƣơng này chúng tôi trình bày nhóm các thành phần chức năng
theo từng cấp độ của chƣơng trình, tạo giao diện và hƣớng dẫn sử dụng
chƣơng trình.
Với đề tài này, chúng tôi hy vọng rằng các bài giảng về đồ thị sẽ trực
quan, dễ hiểu hơn. Kết quả của đề tài cũng là sự thể hiện quá trình tập dƣợt
nghiên cứu của tôi.
2. Mục đích nghiên cứu
Mục đích chính của đề tài là:
- Nghiên cứu về các thuật toán trên đồ thị.
- Tìm hiểu về Phân tích và Thiết kế hệ thống, Kỹ thuật lập trình.
- Sử dụng một ngôn ngữ lập trình để triển khai xây dựng chƣơng trình
mô phỏng các thuật toán trên đồ thị.
3. Nhiệm vụ nghiên cứu
Tìm hiểu các thuật toán trên đồ thị.

Xây dựng chƣơng trình mô phỏng các thuật toán trên đồ thị.
4. Đối tƣợng và phạm vi nghiên cứu
4.1 Đối tƣợng nghiên cứu
- Đồ thị hữu hạn.
- Các kỹ thuật lập trình.
4.2 Phạm vi nghiên cứu
- Tìm hiểu về các thuật toán trên đồ thị: Thuật toán duyệt đồ thị; thuật
toán tìm luồng cực đại Ford–Fulkerson; thuật toán tô màu đồ thị Welsh–Powell .
- Cài đặt chƣơng trình phần mềm mô phỏng các thuật toán trên.
9

5. Phƣơng pháp nghiên cứu
- Nghiên cứu lí thuyết.
- Triển khai cài đặt chƣơng trình:
+ Thiết kế các thuật toán trên đồ thị. Biểu diễn dữ liệu.
+ Viết chƣơng trình mô phỏng các thuật toán trên đồ thị.
+ Chạy thử nghiệm và lƣu trữ các kết quả đạt đƣợc, đánh giá lại kết quả.
6. Kết quả đạt đƣợc
Xây dựng đƣợc một chƣơng trình mô phỏng quá trình thực hiện của các
thuật toán nói trên. Góp phần giúp cho việc giảng dạy các thuật toán một cách
dễ hiểu và trực quan nhất.
10

Chƣơng 1. KIẾN THỨC CHUẨN BỊ

1.1 Tổng quan về thuật toán và mô phỏng thuật toán
1.1.1 Tổng quan về thuật toán
 Khái niệm thuật toán
Thuật toán là một khái niệm cơ bản của Toán học và Tin học. Hiểu
một cách đơn giản, thuật toán là một tập các hƣớng dẫn nhằm thực hiện một

công việc nào đó. Giải một bài toán Tin học là việc đi tìm một lời giải cụ
thể, tƣờng minh để đƣa ra Output của bài toán dựa trên Input đã cho. Việc
chỉ ra một cách tìm Output của bài toán đƣợc gọi là một thuật toán.
Trong thực tế có nhiều cách mô tả khái niệm về thuật toán, dƣới đây
là cách phát biểu đƣợc chọn để đƣa vào sách giáo khoa Tin học phổ thông:
“Thuật toán là một dãy hữu hạn các thao tác được sắp xếp theo một
trình tự nhất định để sau khi thực hiện dãy các thao tác đó, từ input ta có
output cần tìm”
 Các đặc trưng của thuật toán
Dựa trên khái niệm về thuật toán và ví dụ ở trên ta thấy các thao tác
trong thuật toán phải đƣợc mô tả đủ chi tiết để một đối tƣợng cứ tiến hành
thực hiện theo đúng thứ tự các thao tác đó là có thể cho ra output dựa trên
input tƣơng ứng. Một thuật toán phải đảm bảo đƣợc các tính chất sau:
Tính xác định: Sau khi thực hiện một thao tác thì hoặc là thuật toán
kết thúc hoặc là có đúng một thao tác xác định để thực hiện tiếp theo.
Tính đúng đắn: Sau khi thực hiện thuật toán ta phải nhận đƣợc đúng
Output cần tìm.
Tính dừng: Thuật toán phải kết thúc sau một số hữu hạn lần thực hiện.
Tính tổng quát: Thuật toán là đúng đắn với mọi bộ dữ liệu đầu vào
của bài toán.
11

Tính hiệu quả:
- Hiệu quả về thời gian: Ta quan tâm tới thời gian cần thiết để thực
hiện xong thuật toán đó. Thời gian đó phải nằm trong giới hạn cho phép.
- Hiệu quả về không gian: Dung lƣợng bộ nhớ cần thiết để lƣu trữ các
đối tƣợng nhƣ bộ Input, bộ Output, kết quả trung gian và chƣơng trình đƣợc
dùng để thực hiện thuật toán.
- Dễ cài đặt: thuật toán đó liệu có chuyển đƣợc thành chƣơng trình
bằng một ngôn ngữ lập trình nào đó hay không.

Trƣớc khi xây dựng thuật toán cho một bài toán nào đó, trƣớc tiên
phải xác định đƣợc Input và Output là gì, thử trên một số ví dụ cụ thể để
định hƣớng cho việc xây dựng thuật toán.
Nói về thuật toán ngƣời ta thƣờng quan tâm đến tính hiệu quả của nó.
Tính hiệu quả này đƣợc đánh giá dựa trên các chi phí về thời gian và không
gian cần thiết để thực hiện thuật toán. Trong phạm vi luận văn chúng tôi chỉ
quan tâm đến việc mô phỏng thuật toán mà không đi sâu xem xét về các tiêu
chí nêu trên.
1.1.2 Mô phỏng thuật toán
Mô phỏng thuật toán là quá trình mô tả cấu trúc dữ liệu, các thao tác
của một chƣơng trình bằng đồ họa. Mô phỏng thuật toán đƣợc thiết kế nhằm
giúp ngƣời dùng hiểu thuật toán, đánh giá thuật toán và gỡ lỗi khi cài đặt
chƣơng trình.
Một chƣơng trình lập trình trên máy tính sẽ chứa các cấu trúc dữ liệu
của thuật toán mà nó sẽ thực hiện. Trong khi thực hiện chƣơng trình đó, giá
trị thực của cấu trúc dữ liệu thay đổi dựa trên từng bƣớc hoạt động của thuật
toán. Mô phỏng thuật toán sử dụng đồ họa để biểu diễn sự thay đổi trạng thái
của cấu trúc dữ liệu cho từng bƣớc hoạt động của nó một cách trực quan,
khoa học. Trong suốt quá trình biểu diễn, ngƣời dùng có thể quan sát việc
12

thực thi thuật toán theo từng bƣớc để có thể biết chi tiết về thuật toán cũng
nhƣ hiểu một cách tƣờng tận về thuật toán đó.
Yêu cầu đối với mô phỏng thuật toán
Mô phỏng đúng theo thuật toán: Để mô phỏng một thuật toán nào
đó, các bƣớc thực hiện chỉ dẫn trên đồ họa phải phản ánh đúng theo nội
dung của thuật toán đã đƣa ra để đảm bảo rằng ngƣời học học đúng thuật
toán mình yêu cầu.
Cho phép thực hiện theo từng bước: Thông thƣờng, khi học một
thuật toán phải dùng đến chƣơng trình mô phỏng để minh họa trong lúc

học tập hoặc nghiên cứu thì thuật toán đó thƣờng không phải là thuật toán
đơn giản. Vì vậy, việc để cho ngƣời dùng có thể hiểu đƣợc thuật toán
thông qua chƣơng trình mô phỏng thì chƣơng trình đó phải hết sức “mềm
dẻo”: ngoài việc cho phép ngƣời dùng đƣa dữ liệu vào đúng theo chuẩn bị
của họ thì nó còn có thể cho phép chạy thuật toán theo từng bƣớc để họ có
thể tiện theo dõi quá trình thay đổi dữ liệu cũng nhƣ kết quả của thuật
toán sau mỗi bƣớc thực hiện. Ngoài ra, chƣơng trình càng hiệu quả hơn
nếu nó cho phép quan sát lại các bƣớc đã thực hiện.
Mô phỏng thuật toán phải có tính động: Vì công việc của mô phỏng là
mô tả sự thay đổi về cấu trúc dữ liệu sau mỗi bƣớc thực hiện của thuật toán
nên hình ảnh mô phỏng cấu trúc đó cũng phải thay đổi theo từng bƣớc để
ngƣời học nắm bắt đƣợc ý tƣởng của thuật toán.
Có thể thực thi với mọi bộ dữ liệu đầu vào: Thƣờng các thuật toán để
dạy học cho học sinh giỏi và học sinh chuyên Tin đều là những thuật toán
“tốt” và có ứng dụng để giải quyết một lớp bài toán trong tin học. Vì vậy,
chƣơng trình mô phỏng thuật toán cần đảm bảo chạy “tốt” đối với mọi bộ
dữ liệu đầu vào: trƣờng hợp tốt, trƣờng hợp xấu, trƣờng hợp ngẫu nhiên….
Có sự phân cấp người học: Thông thƣờng, mức độ tiếp thu trong
13

một giờ học của học sinh không giống nhau, có những học sinh hiểu bài
nhanh nhƣng cũng có những học sinh nắm bắt bài chậm hơn. Vì vậy,
thuật toán mô phỏng cũng cần phải có những chức năng “mềm dẻo” với
các đối tƣợng học.
1.2 Một số khái niệm cơ bản về đồ thị
1.2.1 Đồ thị
Định nghĩa 1.1. Đồ thị là một cặp
 
,G V E
gồm hai tập hợp hữu hạn

V

E
thoả mãn điều kiện
 
 
, | , ;E x y x y V x y  
.
Phần tử của
V
được gọi là đỉnh, phần tử của
E
được gọi là cạnh của
đồ thị
G
.
Trong định nghĩa này, mỗi phần tử của
E
là một tập hợp gồm hai phần
tử khác nhau thuộc
V
. Nhƣ vậy, các đồ thị đƣợc xét ở đây là các đồ thị hữu
hạn vô hƣớng, không có khuyên và không có cạnh bội.
Ngƣời ta thƣờng biểu diễn đồ thị trên mặt phẳng nhƣ sau: các vòng tròn
nhỏ (rỗng hoặc đặc) biểu thị các đỉnh và nối hai đỉnh bằng một đƣờng liên tục
nếu hai đỉnh đó tạo thành một cạnh trong
G
.

Hình 1.1 Biểu diễn đồ thị trên mặt phẳng

Ví dụ. Ở hình 1.1, biểu diễn đồ thị của:
 
,G V E
với
 
15
, , ,V a a

 
 
 
 
 
 
 
1 2 1 3 1 4 1 5 2 4 3 5
, , , , , , , , , , ,E a a a a a a a a a a a a

 
' ', 'G V E
với
 
' 1, ,7V 
,
         
 
' 1,5 , 2,3 , 2,6 , 2,7 , 6,7E 
.
14


Định nghĩa 1.2. Đồ thị là một cặp
 
,G V E
với V là tập các đỉnh của
đồ thị, E là tập đỉnh các cặp đỉnh
 
,ij
mà các cặp này có thứ tự
 
,ij
khác
trình
 
,ji
. Cặp
 
,ij
gọi là cung của đồ thị có hướng.
Ta nói
 
,G V E
là một đồ thị trên
V
; tập đỉnh của
G
đƣợc ký hiệu là
 
VG
, tập cạnh
 

EG
. Để đơn giản, ta có thể viết “đỉnh
vG
” hay “cạnh
eG
” chứ không nhất thiết phải viết “đỉnh
 
v V G
” hay “cạnh
 
e E G
”.
Số đỉnh của đồ thị
G
đƣợc gọi là cấp (order) của
G
và đƣợc ký hiệu
bằng
G
. Số cạnh của nó đƣợc gọi là cỡ (size) của
G
và ký hiệu là
G
. Nhƣ
vậy
GV
còn
GE
. Một đồ thị có cấp
0

hoặc
1
đƣợc gọi là tầm
thƣờng. Hiển nhiên là nếu một đồ thị có cấp
n
thì cỡ
m
của nó thoả mãn
2
0
n
mC
.
Ta nói đỉnh
v
liên thuộc với cạnh
e
(hay cạnh
e
liên thuộc với đỉnh
v
)
nếu
ve
. Các đỉnh liên thuộc với một cạnh đƣợc gọi là các đầu mút của cạnh
đó. Nếu không có sự nhầm lẫn, cạnh
 
,xy
có thể đƣợc viết gọn thành
xy


(hoặc
yx
).
Hai đỉnh
,xy
của
G
đƣợc gọi là kề nhau hoặc là hàng xóm (của nhau)
nếu
xy
là một cạnh trong
G
. Hai cạnh khác nhau
e

f
của
G
đƣợc gọi là
liền nhau nếu chúng có chung một đầu mút.
Định nghĩa 1.3. Bậc của
v
, ký hiệu bởi
 
deg v
, là số cạnh liên thuộc
với
v
, nghĩa là

   
deg v E v
. Đỉnh bậc
0
được gọi là đỉnh cô lập.
Bậc nhỏ nhất của
G
là số
   
 
min deg |G v v V


; bậc lớn nhất của
G
là số
   
 
max deg |G v v V  

Đối với đồ thị có hƣớng
 
,G V E
. Xét một cung
eE
, nếu
 
,e u v

thì ta nói u nối tới v và v nối từ u, cung e là đi ra khỏi đỉnh u và đi vào đỉnh

15

v. Đỉnh u khi đó đƣợc gọi là đỉnh đầu, đỉnh v đƣợc gọi là đỉnh cuối của cung e.
Với mỗi đỉnh v trong đồ thị có hƣớng, ta định nghĩa: Bán bậc ra của v
ký hiệu
 
deg v

là số cung đi ra khỏi nó; bán bậc vào ký hiệu deg
-
(v) là số
cung đi vào đỉnh đó.
Định nghĩa 1.4. Đồ thị không rỗng
G
được gọi là liên thông nếu hai
đỉnh bất kỳ của nó luôn được nối với nhau bởi một đường trong
G
.
Một đồ thị vô hƣớng gọi là liên thông nếu với mọi cặp đỉnh
 
,uv
ta

u
đến đƣợc
v
. Một đồ thị có hƣớng gọi là liên thông mạnh.
1.2.2 Biểu diễn đồ thị
Khi lập trình giải các bài toán đƣợc mô phỏng hoá bằng đồ thị, việc
đầu tiên cần làm là tìm cấu trúc dữ liệu để biểu diễn đồ thị sao cho việc giải

quyết bài toán đƣợc thuận tiện nhất.
Có rất nhiều phƣơng pháp biểu diễn đồ thị, sau đây là một số phƣơng
pháp phổ biến nhất.
a. Biểu diễn bằng ma trận kề
Giả sử
 
,G V E
là một đơn đồ thị, có số đỉnh (kí hiệu
V
) là n, không
làm mất tính tổng quát có thể coi các đỉnh đƣợc đánh số 1, 2, , n. Khi đó ta
có thể biểu diễn đồ thị bằng một ma trận vuông
 
,A a i j



cấp n. Trong đó:
+
 
,1a i j 
nếu
 
,i j E

+
 
,0a i j 
nếu
 

,i j E

Với
i
giá trị của
 
,a i j
có thể đặt tuỳ theo mục đích, thông thƣờng
nên đặt bằng
0
;
Đối với đa đồ thị thì việc biểu diễn cũng tƣơng tự trên, chỉ có điều nếu
nhƣ
 
,ij
là cạnh thì không phải ta ghi số 1 vào vị trí
 
,a i j
mà là ghi số
cạnh nối giữa đỉnh i và đỉnh j.
16

Ví dụ:

1
G

 
1
0 0 1 1 0

0 0 0 1 1
1 0 0 0 1
1 1 0 0 0
0 1 1 0 0
AG










Hình 1.2 Biểu diễn đồ thị vô hƣớng
1
G
bằng ma trận vuông

2
G

 
2
0 0 1 0 0
0 0 0 1 0
0 0 0 0 1
1 0 0 0 0
0 1 0 0 0

AG










Hình 1.3 Biểu diễn đồ thị có hƣớng
2
G
bằng ma trận vuông
Các tính chất của ma trận kề
Đối với đồ thị vô hƣớng G, thì mà trận kề tƣơng ứng là ma trận đối
xứng
   
 
,,a i j a j i
, điều này không đúng với đồ thị có hƣớng.
Nếu G là đồ thị vô hƣớng và A là ma trận kề tƣơng ứng thì trên ma trận
A: Tổng các số trên hàng i = Tổng các số trên cột i = Bậc của đỉnh
 
degii

Nếu G là đồ thị có hƣớng và A là ma trận kề tƣơng ứng thì trên ma trận A:
+ Tổng các số trên hàng i = Bán bậc ra của đỉnh
 

degii



+ Tổng các số trên cột i = Bán bậc vào của đỉnh
 
degii



Trong trƣờng hợp G là đơn đồ thị, ta có thể biểu diễn ma trận kề A
tƣơng ứng là các phần tử logic.
 
,a i j TRUE
nếu
 
,i j E

 
,a i j FALSE
nếu
 
.i j E
.
17

Ưu điểm của ma trận kề
Đơn giản, trực quan, dễ cài đặt trên máy tính.
Để kiểm tra xem hai đỉnh
 

,uv
của đồ thị có kề nhau hay không, ta chỉ
việc kiểm tra bằng một phép so sánh:
 
,0a u v 
.
Nhược điểm của ma trận kề
Bất kể số cạnh của đồ thị nhiều hay ít, ma trận kề luôn đòi hỏi
2
n
ô
nhớ để lƣu các phần tử ma trận, điều đó gây lãng phí bộ nhớ dẫn tới việc
không thể biểu diễn đƣợc đồ thị với số đỉnh lớn.
Với một đỉnh
u
bất kỳ, nhiều khi ta phải xét tất cả các đỉnh
v
khác kề
với nó, hoặc xét tất cả các cạnh liên thuộc với nó. Trên ma trận kề việc đó
đƣợc thực hiện bằng cách xét tất cả các đỉnh v và kiểm tra điều kiện
 
,0a u v 
. Nhƣ vậy, ngay cả khi đỉnh u là đỉnh cô lập (không kề với đỉnh
nào) hoặc đỉnh treo (chỉ kề với một đỉnh) ta cũng buộc phải xét tất cả các
đỉnh và kiểm tra điều kiện trên dẫn tới lãng phí thời gian.
b. Danh sách cạnh
Trong trƣờng hợp đồ thị có n đỉnh, m cạnh, ta có thể biểu diễn đồ thị
dƣới dạng danh sách cạnh bằng cách liệt kê tất cả các cạnh của đồ thị trong
một danh sách, mỗi phần tử của danh sách là một cặp
 

,uv
tƣơng ứng với
một cạnh của đồ thị. (Trong trƣờng hợp đồ thị có hƣớng thì mỗi cặp
 
,uv

tƣơng ứng với một cung, u là đỉnh đầu và v là đỉnh cuối của cung). Danh sách
đƣợc lƣu trong bộ nhớ dƣới dạng mảng hoặc danh sách móc nối. Ví dụ đồ thị
ở hình 1.4 dƣới đây:

Hình 1.4 Ví dụ đồ thị vô hƣớng 5 đỉnh
18

Cài đặt trên mảng:

Hình 1.5 Đồ thị cài đặt trên mảng
Cài đặt trên danh sách móc nối

Hình 1.6 Đồ thị cài đặt trên danh sách móc nối
Ưu điểm của danh sách cạnh
Trong trƣờng hợp đồ thị thƣa (số cạnh tƣơng đối nhỏ: chẳng hạn
6mn
), cách biểu diễn bằng danh sách cạnh sẽ tiết kiệm đƣợc không gian
lƣu trữ, bởi nó chỉ cần 2m ô nhớ để lƣu danh sách cạnh.
Trong một số trƣờng hợp, ta phải xét tất cả các cạnh của đồ thị thì cài
đặt trên danh sách cạnh làm cho việc duyệt các cạnh dễ dàng hơn.
Nhược điểm của danh sách cạnh
Nhƣợc điểm cơ bản của danh sách cạnh là khi ta cần duyệt tất cả các
đỉnh kề với đỉnh v nào đó của đồ thị, thì chẳng có cách nào khác là duyệt tất
cả các cạnh, lọc ra những cạnh có chứa đỉnh v và xét đỉnh còn lại. Điều đó

khá tốn thời gian trong trƣờng hợp đồ thị dày (nhiều cạnh).
c. Danh sách kề
Để khắc phục phƣơng pháp ma trận kề và danh sách cạnh, ngƣời ta đề
xuất phƣơng pháp biểu diễn đồ thị bằng danh sách kề. Trong cách biểu diễn
này, với mỗi đỉnh v của đồ thị, ngƣời ta cho tƣơng ứng bộ danh sách các đỉnh
kề với v.
Với đồ thị
 
,G V E
. V gồm n đỉnh và E gồm m cạnh. Có hai cách cài
đặt danh sách kề phổ biến:
Cách 1: Dùng một mảng các đỉnh, mảng đó chia làm n đoạn, đoạn thứ i
19

trong mảng lƣu danh sách các đỉnh kề với đỉnh i: Với đồ thị Hình 1.4 danh
sách các đỉnh kề với i sẽ là một mảng Adj gồm 12 phần tử:

Hình 1.7 Danh sách kề của mảng Adj gồm 12 phần tử
Để biết một đoạn nằm từ chỉ số nào đến chỉ số nào, ta có một mảng
Head lƣu vị trí riêng.
 
Head i
sẽ bằng chỉ số đứng liền trƣớc đoạn thứ i. Quy
ƣớc
 
1Head n 
bằng m. Với đồ thị bên thì mảng
 
1 6Head
sẽ là

 
0,3,5,8,10,12
.
Các phần tử
   
1 1Adj Head i Head i



sẽ chứa các đỉnh kề với
đỉnh i. Lƣu ý rằng với đồ thị có hƣớng gồm m cung thì cấu trúc này cần đủ
chứa m phần tử, với đồ thị vô hƣớng m cạnh thì cấu trúc này cần phải đủ
chứa 2m phần tử.
Cách 2. Dùng các danh sách móc nối: Với mỗi đỉnh i của đồ thị, ta cho
tƣơng ứng với nó một danh sách móc nối các đỉnh kề với i, có nghĩa là tƣơng
ứng với một đỉnh i, ta phải lƣu lại
 
List i
là chốt của một danh sách móc nối.
Ví dụ Hình 1.4, các danh sách móc nối sẽ là:

Hình 1.8 Danh sách móc nối của đồ thị
20

Ưu điểm của danh sách kề: Đối với danh sách kề, việc duyệt tất cả các
đỉnh kề với một đỉnh v cho trƣớc là hết sức dễ dàng, cái tên “danh sách kề”
đã cho thấy rõ điều này. Việc duyệt tất cả các cạnh cũng đơn giản vì một
cạnh thực ra là nối một đỉnh với một đỉnh khác kề nó.
Nhược điểm của danh sách kề: Danh sách kề yếu hơn ma trận kề ở
việc kiểm tra

 
,uv
có phải là cạnh hay không, bởi trong cách biểu diễn này
ta sẽ phải duyệt toàn bộ danh sách kề của u hay danh sách kề của v.
Nhận xét
Đối với những thuật toán mà ta sẽ khảo sát, danh sách kề tốt hơn hẳn
so với hai phƣơng pháp biểu diễn trƣớc. Chỉ có điều, trong trƣờng hợp cụ thể
mà ma trận kề hay danh sách cạnh không thể hiện nhƣợc điểm thì ta nên
dùng ma trận kề hay danh sách cạnh bởi cài đặt danh sách kề có phần dài
dòng hơn.
Trên đây là nêu các cách biểu diễn đồ thị trong bộ nhớ máy tính, còn
nhập dữ liệu cho đồ thị thì có nhiều cách khác nhau, dùng cách nào thì tuỳ ý.
Chẳng hạn nếu biểu diễn bằng ma trận kề mà cho nhập dữ liệu cả ma trận cấp
nxn (n là số đỉnh) thì khi nhập từ bàn phím sẽ mất rất nhiều thời gian, ta cho
nhập kiểu danh sách cạnh cho nhanh. Chẳng hạn mảng A(nxn) là ma trận kề
của một đồ thị vô hƣớng thì ta có thể khởi tạo ban đầu mảng A gồm toàn bộ
số
0
, sau đó cho ngƣời sử dụng nhập các cạnh bằng cách nhập các cặp
 
,ij
;
chƣơng trình sẽ tăng
 
,A i j

 
,A j i
lên 1. Việc nhập có thể cho kết thúc
khi ngƣời sử dụng nhập giá trị

0i 
.
Trong nhiều trƣờng hợp đủ không gian lƣu trữ, việc chuyển đổi từ cách
biểu diễn nào đó sang cách biểu diễn khác không có gì khó khăn. Nhƣng đối
với thuật toán này thì làm trên ma trận kề ngắn gọn hơn, đối với thuật toán
kia có thể làm trên danh sách cạnh dễ dàng hơn v.v

21

1.3 Giới thiệu một số bài toán trên đồ thị
1.3.1 Bài toán tìm kiếm
Một bài toán quan trọng trong lí thuyết đồ thị là bài toán duyệt tất cả
các đỉnh có thể đến đƣợc từ một đỉnh xuất phát nào đó. Vấn đề này đƣa về
một bài toán liệt kê mà yêu cầu của nó là không đƣợc bỏ sót hay lặp lại bất kỳ
đỉnh nào. Chính vì vậy mà ta phải xây dựng những thuật toán cho phép duyệt
một cách hệ thống các đỉnh, những thuật toán nhƣ vậy gọi là thuật toán tìm
kiếm trên đồ thị. Ta quan tâm đến hai thuật toán cơ bản nhất: thuật toán tìm
kiếm theo chiều sâu và thuật toán tìm kiếm theo chiều rộng.
Giới thiệu thuật toán tìm kiếm DFS
Tƣ tƣởng của thuật toán có thể trình bày nhƣ sau: Ta sẽ bắt đầu tìm
kiếm từ một đỉnh
0
v
nào đó của đồ thị. Sau đó chọn
u
là một đỉnh tuỳ ý kề với
0
v
và lặp lại quá trình đối với
u

. Ở bƣớc tổng quát, giả sử ta đang xét đỉnh
v
.
Nếu nhƣ trong số các lặp lại bất kỳ đỉnh nào. Vì vậy, cần phải xây dựng
những thuật toán cho phép đỉnh kề với
v
tìm đƣợc đỉnh
w
là chƣa đƣợc xét thì
ta sẽ xét đỉnh này (nó sẽ trở thành đã xét) và bắt đầu từ nó ta tiếp tục quá trình
tìm kiếm. Còn nếu nhƣ không còn đỉnh nào kề với
v
là chƣa xét thì ta nói rằng
đỉnh này đã duyệt xong và quay trở lại tiếp tục tìm kiếm từ đỉnh mà trƣớc đó ta
đến đƣợc từ đỉnh
v
(nếu
0
vv
thì kết thúc tìm kiếm).
Có thể nói nôm na là tìm kiếm theo chiều sâu, bắt đầu từ đỉnh
v
đƣợc
thực hiện trên cơ sở tìm kiếm theo chiều sâu từ tất cả các đỉnh chƣa xét kề với
v
. Quá trình này có thể mô tả bởi thủ tục đệ qui sau đây:
Procedure
 
DFS v
;

Begin
Tham_dinh(v);
Chuaxet[v]:=false;
For
()u ke v
do
If chuaxet[u] then DFS(u);
22

end; (*đỉnh v đã duyệt xong*)
Trong quá trình cài đặt chƣơng trình, chúng tôi không sử dụng thủ tục
 
DFS v
đệ qui ở trên mà sử dụng thủ tục
 
DFS v
khử đệ qui sau đây:
Procedure DFS(v);
Begin
StackInit(P); Push(v); Visit(v);
Chuaxet(v):=false;
While Not StackEmpty(P) do
Begin
While

u

ke(Top(P)) & chuaxet(u) do
Begin
Chuaxet(u):=false;

Push(u); Visit(u);
End;
Tem:=Pop;
End;
End;
Khi đó, tìm kiếm theo chiều sâu trên đồ thị đƣợc thực hiện nhờ thuật
toán sau:
BEGIN
For
vV
do chuaxet[v]:=true;
For
vV
do
If chuaxet[v] then DFS(v);
END.
Ví dụ: Xét đồ thị dƣới đây, đỉnh xuất phát S=1.

Hình 1.9 Đồ thị vô hƣớng 6 đỉnh, đỉnh xuất phát S=1
23

Bƣớc
lặp
Ngăn xếp
u
v
Ngăn xếp sau mỗi
bƣớc
Giải thích
1

(1)
1
2
(1,2)
Tiến sâu xuống thăm 2
2
(1,2)
2
3
(1,2,3)
Tiến sâu xuống thăm 3
3
(1,2,3)
3
5
(1,2,3,5)
Tiến sâu xuống thăm 5
4
(1,2,3,5)
5
Không có
(1,2,3)
Lùi lại
5
(1,2,3)
3
Không có
(1,2)
Lùi lại
6

(1,2)
2
4
(1,2,4)
Tiến sâu xuống thăm 4
7
(1,2,4)
4
6
(1,2,4,6)
Tiến sâu xuống thăm 6
8
(1,2,4,6)
6
Không có
(1,2,4)
Lùi lại
9
(1,2,4)
4
Không có
(1,2)
Lùi lại
10
(1,2)
2
Không có
(1)
Lùi lại
11

(1)
1
Không có


Lùi hết dây chuyền, Xong

Hình 1.10 Minh hoạ ví dụ về thuật toán DFS dạng bảng
Rõ ràng lệnh gọi
 
DFS v
sẽ cho phép đến thăm tất cả các đỉnh thuộc
cùng thành phần liên thông với đỉnh
v
, bởi vì sau khi thăm đỉnh là lệnh gọi đến
thủ tục DFS đối với tất cả các đỉnh kề với nó. Mặt khác, do mỗi khi thăm đỉnh v
xong, biến
 
chuaxet v
đƣợc đặt lại giá trị false nên mỗi đỉnh sẽ đƣợc thăm
đúng một lần. Thuật toán lần lƣợt sẽ tiến hành tìm kiếm từ các đỉnh chƣa đƣợc
thăm, vì vậy nó sẽ xét qua tất cả các đỉnh của đồ thị (không nhất thiết phải là
liên thông).
Giới thiệu thuật toán tìm kiếm BFS
Cơ sở của phƣơng pháp cài đặt này là “lập lịch” duyệt các đỉnh. Việc
thăm một đỉnh sẽ lên lịch duyệt các đỉnh kề với nó sao cho thứ tự duyệt là ƣu
tiên chiều rộng (đỉnh nào gần S hơn sẽ đƣợc duyệt trƣớc) .
Giả sử ta có một danh sách chứa những đỉnh đang “chờ” thăm. Tại mỗi
bƣớc ta thăm một đỉnh đầu danh sách và cho những đỉnh chƣa “xếp hàng” kề
với nó xếp hàng thêm vào cuối danh sách. Chính vì nguyên tắc đó nên danh

24

sách chứa những đỉnh đang chờ sẽ đƣợc tổ chức dƣới dạng hàng đợi
(QUEUE).
Để ý rằng trong thuật toán tìm kiếm theo chiều sâu đỉnh đƣợc thăm
càng muộn sẽ càng sớm trở thành đã duyệt xong. Điều đó là hệ quả tất yếu
của các đỉnh đƣợc thăm sẽ đƣợc kết nạp vào trong ngăn xếp (STACK). Tìm
kiếm theo chiều rộng trên đồ thị, nếu nói một cách ngắn gọn, đƣợc xây dựng
trên cơ sở thay thế ngăn xếp bởi hàng đợi (QUEUE). Với sự cải biên nhƣ
vậy, đỉnh đƣợc thăm càng sớm, sẽ càng sớm trở thành đã duyệt xong (tức là
càng sớm rời khỏi hàng đợi). Một đỉnh sẽ trở thành đã duyệt xong ngay sau
khi ta xét xong tất cả các đỉnh kề (chƣa đƣợc thăm) với nó. Thủ tục có thể mô
tả nhƣ sau:
Procedure BFS(v);
Begin
QUEUE:=

;
Put(v); (*Kết nạp v vào QUEUE *)
Chuaxet[v]:=false;
While QUEUE

do
begin
get(p); (*Lấy p từ QUEUE*)
visit(p);
for
u
ke(p) do
if chuaxet[u] then

begin
put(u);
chuaxet[u]:=false;
end;
end;
end;

×