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

Báo cáo học thuật đề tài thuật toán gán nhãn đồ thị và lập trình tìm đường đi ngắn nhất bằng thuật toán disjstra

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 (4.65 MB, 35 trang )

BỘ GIÁO DỤC VÀ ĐÀO TẠO

TRƯỜNG ĐẠI HỌC MỎ - ĐỊA CHẤT
-----------------------------------------

BÁO CÁO HỌC THUẬT
Đề tài: Thuật toán gán nhãn đồ thị và lập trình tìm đường đi
ngắn nhất bằng thuật tốn Disjstra

Người thực hiện: Nguyễn Tuấn Anh
Bộ mơn: Mạng máy tính – Khoa Cơng nghệ thơng tin

Hà nội- 6/2022

1


MỤC LỤC

CHƯƠNG 1- KHÁI NIỆM VÀ CÁC DẠNG ĐỒ THỊ ......................................................... 4
1.1. ĐỊNH NGHĨA ĐỒ THỊ VÀ CÁC KHÁI NIỆM .............................................................. 4
1.1.1. Định nghĩa đồ thị ................................................................................................... 4
1.1.2. Đồ thị có hướng và khơng có hướng ..................................................................... 4
1.1.3. Đỉnh kề

................................................................................................... 5

1.1.4. Cạnh liên thuộc ................................................................................................... 5
1.1.5. Bậc của đỉnh

................................................................................................... 5



1.2. ĐƯỜNG ĐI VÀ CHU TRÌNH .................................................................................... 6
1.2.1. Đường đi

................................................................................................... 6

1.2.2. Chu trình

................................................................................................... 6

1.2.3. Đồ thị có trọng số và khơng có trọng số................................................................. 6
1.2.4. Đơn đồ thị, đa đồ thị và đồ thị con ......................................................................... 6
CHƯƠNG 2-BIỂU DIỄN ĐỒ THỊ TRÊN MÁY TÍNH ........................................................ 9
2.1.BIỂU DIỄN ĐỒ THỊ BẰNG MA TRẬN KỀ.................................................................. 9
2.2. BIỂU DIỄN ĐỒ THỊ BẰNG DANH SÁCH CẠNH..................................................... 12
2.3. BIỂU DIỄN ĐỒ THỊ BẰNG DANH SÁCH LÂN CẬN KỀ.......................................... 16
CHƯƠNG 3- ĐƯỜNG ĐI NGẮN NHẤT ........................................................................ 19
3.1.KHÁI NIỆM VỀ ĐƯỜNG ĐI VÀ ĐƯỜNG ĐI NGẮN NHẤT ...................................... 19
3.2.THUẬT TOÁN GÁN NHÃN ĐỒ THỊ GIẢI BÀI TOÁN 1 ............................................ 20
3.3.THUẬT TOÁN DIJKSTRA GIẢI BÀI TOÁN 2 ........................................................... 25


LỜI NĨI ĐẦU

Trong thực tế có rất nhiều bài tốn liên quan tới một tập các đối tượng và
những mối liên hệ giữa chúng, địi hỏi tốn học phải đặt ra mơ hình biểu diễn một
cách chặt chẽ và tổng quát bằng ngôn ngữ ký hiệu. Những ý tưởng cơ bản của đồ
thị được đưa ra từ thế kỷ thứ XVIII bởi nhà tốn học Thụy Sĩ Leonhard Euler từ
mơ hình đồ thị để giải bài tốn về những cây cầu Künigsburg nổi tiếng.
Lý thuyết đồ thị đã được khoa học phát triển từ rất lâu và ngày càng có nhiều

ứng dụng. Đến ngày nay, với sự ra đời của máy tính điện tử và sự phát triển nhanh
chóng của tin học, Lý thuyết đồ thị càng được quan tâm nhiều hơn, các thuật tốn
trên đồ thị đã có nhiều ứng dụng trong nhiều lĩnh vực khác nhau như: mạng Máy
tính, Đồ hoạ máy tính, Lý thuyết mã, Tối ưu hoá, Kinh tế học,…

3


CH
CHƯƠNG
ƯƠNG 1
1-- KHÁI NI
NIỆ
ỆM VÀ CÁC D
DẠNG
ẠNG ĐỒ TH
THỊỊ
1.1. ĐỊNH NG
NGHĨA
HĨA ĐỒ TH
THỊỊ VÀ CÁC KHÁI N
NIIỆM
1.1.1. Định nghĩa đồ thị

Một đồ thị G bao gồm một tập hợp hữu hạn V, mà mỗi phần tử được gọi là
đỉnh (hoặc nút) và một tập hợp E gồm các cặp hai đỉnh u và v dạng e = (u, v). Ký
hiệu đồ thị G là G = (V, E).
Tập V là hữu hạn, có nghĩa là ta có thể đánh số thứ tự là 1, 2, 3,... hoặc a, b,
c,... cho các phần tử (hay các đỉnh) của V. Ta quy ước khi nói đến đồ thị G thì số
đỉnh của đồ thị là n, số cạnh (hay cung) m tức là |V| = n, |E| = m.

1.1.2. Đồ thị có hướng và khơng có hướng

Giả sử u và v là hai đỉnh của đồ thị G = (V, E), nếu cặp
(u, v)  E có kể đến thứ tự u là đỉnh đầu, v là đỉnh cuối thì ta gọi đó là đồ thị có
hướng, khi đó mỗi e = (u, v) được gọi là cung (hình 1.1).
2
3

1

5

4

Hình 1.1. Đồ thị có hướng

Ngược lại ta gọi đó là đồ thị vơ hướng (hay đồ thị khơng có hướng) và (u, v)
gọi là cạnh nối đỉnh u, v và cũng ký hiệu là e = (u, v)  E (hình 1.2).

1

2

4

3

5

Hình 1.2. Đồ thị vô hướng



Bằng hình vẽ ta có thể biểu diễn mỗi đỉnh của đồ thị bởi một điểm trên mặt
phẳng, mỗi cạnh bởi một đường nối hai điểm tương ứng hai đỉnh. Với đồ thị có
hướng ta thêm vào cạnh một mũi tên hướng từ đỉnh đầu tới đỉnh cuối.
1.1.3. Đỉnh kề

Cho đồ thị G = (V, E) là đồ thị vô hướng và đỉnh xV, hai đỉnh nằm trên cùng
một cạnh gọi là hai đỉnh kề nhau, ký hiệu V(x) là tập con của V, gồm những đỉnh
kề với x. Trường hợp G là đồ thị có hướng, ký hiệu V+(x) = {y  V: (x, y)  E} –
tập các đỉnh kề sau của x; V−(x) = {y  V: (y, x)  E} – Tập các đỉnh kề trước của
x.
Trong hình 1.2 thì V(1) = {2, 4, 5}; trong hình 1.1 thì
V+(4) = {2, 3}, V−(4) = {5}.
1.1.4. Cạnh liên thuộc

Nếu u  V, v  V và e = (u, v)  E ta nói rằng u, v là 2 đỉnh kề nhau và cạnh
e liên thuộc với đỉnh u và đỉnh v. Ví dụ cạnh (1, 5) trong hình 1.2 là cạnh liên
thuộc với đỉnh 1 và đỉnh 5.
1.1.5. Bậc của đỉnh

Với mỗi đỉnh v của đồ thị, ta định nghĩa bậc (degree) của đỉnh v ký hiệu
deg(v) là số cạnh liên thuộc với v hoặc là số đỉnh kề của v. Trên đồ thị hình 1.2 thì
bậc của đỉnh 1 là 3; bởi vì đỉnh 3 có các đỉnh kề là 2, 4 và 5.
Định lý: Giả sử G = (V, E) là đồ thị vô hướng m cạnh, khi đó tổng tất cả bậc
của các đỉnh trong V của đồ thị được tính bằng cơng thức:

 deg( v) = 2m
vV


Hệ quả: Trong đồ thị vô hướng, số đỉnh bậc lẻ là một số chẵn.
Đối với mỗi đồ thị có hướng G = (V, E), xét một cung e E, 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 u và đi vào v. Đỉnh u khi đó là
đỉnh đầu, đỉnh v được gọi là đỉnh cuối của cung e.
Bán bậc ra và bán bậc vào
− Bán bậc ra là số cung đi ra từ đỉnh v, ký hiệu deg+(v)
− Bán bậc vào là số cung đi vào đỉnh v: ký hiệu deg−(v)
− Trong hình 1.1 thì bán bậc vào đỉnh 4 là 1 và bán bậc ra là 2.
deg+(4) = 2;
deg−(4) = 1.
5


Định lý :

 deg
vV

+

(v) = deg− (v)
vV

1.2. ĐƯ
ĐƯỜNG
ỜNG ĐI VÀ CHU TRÌN
TRÌNH
H
1.2.1. Đường đi


Cho hai đỉnh u và v của đồ thị G, một đường đi từ đỉnh u đến đỉnh v, ký hiệu
(u, v) là dãy các đỉnh u, p1, p2,..., pk, v xác định bởi dãy (u, p1), (p1, p2),…, (pk, v)
các cạnh (hoặc cung của G nếu G là đồ thị có hướng). Số lượng các cạnh(hoặc
cung) trên đường đi gọi là độ dài của đường đi. Đỉnh u được gọi là đỉnh đầu, đỉnh
v được gọi là đỉnh cuối.
Trong trường hợp u  v, người ta nói rằng (u, v) là đường đi khép kín. Nếu
đường đi (u, v), mỗi cạnh (cung) có mặt khơng q một lần thì được gọi là đường
đi đơn.
1.2.2. Chu trình

Chu trình là một đường đi khép kín (đỉnh cuối trùng với đỉnh đầu của đường
đi), ký hiệu là: {u, p1, p2,..., pk, v}, trong đó u  v.
1

4

2

5

3

Chu trình: {1, 2, 5, 1}

6

Hình 1.3. Đồ thị có chu trình

1.2.3. Đồ thị có trọng số và khơng có trọng số


Đồ thị G mà mỗi cạnh của nó đều được gắn với một số không âm, thể hiện
thông tin liên quan tới cạnh đó, gọi là đồ thị có trọng số. Nói cách khác đồ thị có
trọng số nếu có ánh xạ f: E→ R+; trong đó E là tập cạnh, R+ là tập số thực không
âm w= f(u, v) gọi là trọng số của cạnh (u, v)  E.
Đồ thị mà mỗi cạnh khơng được gắn trọng số thì ta gọi đó là đồ thị khơng có
trọng số.
Trọng số của đồ thị được mở rộng tự nhiên cho đồ thị có hướng.
1.2.4. Đơn đồ thị, đa đồ thị và đồ thị con

• Đơn đồ thị


Đơn đồ thị là đồ 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ạnh thỏa mãn khơng có hai cạnh có chung cả hai đỉnh (khơng có cạnh lặp)

Hình 1.4.Đơn đồ thị

• Đa đồ thị
Đa
đồ
thị

đồ
thị

hướng
G = (V, E) bao gồm V là tập các đỉnh, và E là tập các cạnh trong đó một cặp
(khơng có thứ tự) hai phần tử khác nhau của V có thể xác định nhiều 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; ví
dụ (3, 5) và (5, 3), hình 1.5.

1

2

3
4

5

Hình 1.5. Đa đồ thị

Chú ý: Khi G là đa đồ thị, dãy các đỉnh trong định nghĩa đường đi có thể xác
định nhiều đường đi khác nhau. Trong trường hợp đó, đường đi xác định bằng dãy
các cạnh sẽ rõ ràng hơn.
• Đồ thị con
Đồ thị con của đồ thị G là đồ thị mà tập cạnh và tập đỉnh của nó là các tập con
của các thành phần tương ứng của G.
1

2

2

4

3

3

Đồ thị H = (W, F) trong đó,

W = {1, 2, 3, 4} và F = {(1,
2), (1, 4), (2, 3), (2, 4), (3,
4)} là đồ thị con của đồ thị
G bởi vì W  V, F  E.

Hình 1.6. Đồ thị con của m ột đồ thị

7


Cho G = (V, E) ; tập V1  V. Đồ thị con có tập đỉnh V1 và tập cạnh chứa tất cả
các cạnh của G nối hai đỉnh thuộc V1 gọi là đồ thị con sinh bởi V1.
Chú ý: Thuật ngữ đồ thị trong mỗi ngữ cảnh để ngắn gọn và cũng khơng gây
nhầm lẫn có thể được hiểu là đơn đồ thị, đồ thị vô hướng hay đồ thị có hướng.


CH
CHƯƠNG
ƯƠNG 2
2--BI
BIỂ
ỂU DI
DIỄ
ỄN ĐỒ TH
THỊỊ TRÊN MÁ
MÁY
Y TÍNH
Người ta có thể biểu diễn đồ thị trên mặt phẳng dưới dạng các điểm ứng với
các đỉnh và các đường nối chúng với nhau ứng với các cạnh. Để sử dụng máy tính
giải các bài tốn được mơ tả bởi mơ hình đồ thị người ta phải tìm cách khác để mơ

tả đồ thị. Việc lựa chọn các cấu trúc dữ liệu khác nhau để mơ tả đồ thị trên máy
tính phụ thuộc vào bài toán cần giải và thuật toán được lựa chọn. Trong chương
này chúng ta xem xét đồ thị G = (V, E) với |V| = n, |E| = m (n: số đỉnh, m: số
cạnh).
2.1.
2.1.BI
BI
BIỂ
ỂU DIỄN Đ
ĐỒ
Ồ TH
THỊỊ BẰNG M
MA
A TR
TRẬ
ẬN K
KỀ

Cho đồ thị G = (V, E) có tập đỉnh V = {v1, v2,…., vn} và tập các cạnh E, ma
trận kề của đồ thị là ma trận vng A kích thước nxn (có n hàng và n cột), gồm các
số 0 và 1. Với i, j {1, 2,…, n}, phần tử aij = 1 nếu (vi, vj)  E và aij = 0 trong
trường hợp ngược lại.
2

1

3

5


4

Hình 2.1. Đồ thị vơ hướng khơng có trọng số

Ví dụ đồ thị cho trong hình 2.1 được biểu diễn bởi ma trận kề A như sau:

0
1

A = 0

1

0

1
0

0
0

1
0

0

0

1


0
1

1
1

0
1

0
1

1

1
0
 5 x5

Hiển nhiên, với một đồ thị ma trận kề phụ thuộc vào thứ tự đánh số các đỉnh.
Ma trận kề có một số tính chất sau:
− Ma trận kề của đồ thị vô hướng là đối xứng.
− Ma trận kề của đồ thị có hướng nói chung khơng có tính đối xứng.
− aii = 0 với mọi i = 1, 2,..., n.
− Tổng các giá trị trên hàng i (hay cột j) bằng bậc của đỉnh vi (hay vj) của đồ thị
vô hướng.
9


Có thể hiểu đồ thị G = (V, E) như là đồ thị có trọng số và trọng số f(u, v) =1
nếu (u, v)  E và f(u, v)=0 trong trường hợp ngược lại, khi đó với đồ thị có trọng

số ta có thể lập ma trận trọng số tương tự ma trận kề với aij = f(vi, vj) − trọng số
cung (vi, vj) nếu cung (vi, vj)  E và aij =  trong trường hợp ngược lại. ở đây  là
giá trị được chọn tuỳ theo từng trường hợp cụ thể. Với hình 1.4 thì ta có ma trận
trọng số biểu diễn sơ đồ đường sắt Bắc Nam như sau:
150
250
 0
 150
0
200

 250
200
0

210 5000 5000
A =
5000 5000 5000

5000 5000 5000
5000 5000 5000

5000 5000 5000

5000 
5000 
5000 5000 

5000 5000 
Ta gán  =

5000 1300 

200 5000 
0
120 

120
0  8x 8

210

5000

5000

5000

5000

5000

5000

5000

5000
0

5000
400


5000
5000
320

400

0

5000

320

0

5000

5000

200

5000 1300

5000

5000 bởi vì thực tế chiều dài lãnh thổ của nước ta cũng chỉ khoảng hơn 2000 km
từ Bắc vào Nam và gán aii = 0 cho biết khơng có cung (vi, vi), hay khoảng cách vi
đến vi là 0.
Với bài toán này ta cũng sẽ lưu số liệu vào tệp tin là dothi14.inp.


Hình 2.2. Tệp số liệu đồ thị của hình 1.4

Đối với đồ thị có hướng chúng ta cũng lưu số liệu tương tự như đồ thị vơ
hướng, ví dụ đồ thị hình 2.3 sẽ được lưu số liệu vào tệp tin dothi23.inp.
2
3
1

5

4

Hình 2.3. Đồ thị có hướng khơng trọng số


Hình 2.4. Tệp số liệu đồ thị của hình 2.3

Đối với đồ thị có hướng và có trọng số chúng ta cũng lưu số liệu tương tự như
đồ thị có hướng, ví dụ đồ thị hình 2.3 sẽ được lưu số liệu vào tệp tin dothi25.inp.
120

2
100

100
1

120
110


5

3
80
180

125

4

Hình 2.5. Đồ thị có hướng có trọng số

Hình 2.6. Tệp số liệu đồ thị của hình 2.5

Sau đây ta sẽ xây dựng chương trình thao tác trên ma trận kề, trước tiên ta mở
chương trình Notepad.exe của Window và soạn thảo một tệp tin dạng văn bản có
tên là dothi21.inp, (số 21 trong tên của tệp tin có nghĩa là tệp số liệu của đồ thị
hình 2.1) có nội dung như sau:

Hình 2.7. Tệp số liệu đồ thị của hình 2.1

11


2.2. BI
BIỂ
ỂU DIỄN ĐỒ TH
THỊỊ BẰNG DANH SÁCH CẠNH
Trong trường hợp G = (V, E) là đồ thị thưa ta có thể biểu diễn đồ thị bởi danh
sách cạnh. Các cạnh của đồ thị được sắp xếp theo một thứ tự nào đó dạng (u, v)

trong đó u là đỉnh đầu, v là đỉnh cuối.
2

3

1

4

Hình 2.8. Đồ thị vơ hướng khơng có trọng số

Ví dụ, danh sách cạnh của đồ thị vơ hướng khơng có trọng số cho trong hình
2.9, được biểu diễn như bảng sau:
Danh sách cạnh biểu diễn của đồ thị trên hình 2.9
Đỉnh đầu

Đỉnh cuối

1

2

1

4

2

3


2

4

3

4

Như vậy, ta khai báo một cấu trúc dữ liệu có tên là cạnh – Canh để lưu trữ
đỉnh đầu và đỉnh cuối của mỗi cạnh trong đồ thị như sau:
typedef struct Canh
{
int dau, cuoi; // dau: đỉnh đầu của cạnh
// cuoi: đỉnh cuối của cạnh
};
Canh E[MAX]; // Khai báo E là danh sách cạnh của
// đồ thị khơng có trọng số

Hình ảnh danh sách kề của đồ thị hình 2.4 được lưu trong mảng G như sau:
(1, 2)

(1, 4)

(2, 3)

(2, 4)

(3, 4)

E[1]


E[2]

E[3]

E[4]

E[5]


Với đồ thị hình 2.9, ta cũng sử dụng Notepad để soạn thảo tệp dữ liệu dưới
đây:

Hình 2.9. Tệp số liệu đồ thị hình 2.9

Trong tệp dothi29.inp, dịng thứ nhất có hai thành phần là 4 và 5; trong đó
thành phần thứ nhất là số 4 cho biết số đỉnh của đồ thị
(n = 4) và thành phần thứ hai là số 5 cho biết đồ thị có 5 cạnh
(m = 5). Các dòng còn lại, tại mỗi dòng cho biết thành phần thứ nhất là số hiệu
đỉnh đầu, và thành phần thứ hai là số hiệu đỉnh cuối của mỗi cạnh tương ứng trong
đồ thị.
Nếu trường hợp đồ thị có trọng số thì trọng số có thể được mơ tả ở bên cạnh,
với đồ thị hình 2.11 ta sẽ thêm một thành phần nữa là trọng số của cạnh như sau:
2
5

1

4
3


5

1
1
4

4
4

Hình 2.10. Đồ thị vơ hướng có trọng số

Danh sách cạnh biểu diễn của đồ thị trên hình 2.11
Đỉnh đầu

Đỉnh cuối

Trọng số

1

2

5

1

4

4


2

3

4

2

5

1

13


3

4

4

4

5

1

typedef struct Canh
{

int dau, cuoi;
float trongso;
};
Canh E[MAX]; //
Khai
báo
E

// đồ thị có trọng số

danh

sách

cạnh

của

Đồ thị hình 2.11 được lưu trữ trên tệp như sau:

Hình 2.11. Tệp số liệu đồ thị hình 2.11

Mỗi dịng gồm có 3 giá trị, ví dụ: 1 2 5 trong đó: 1 là đỉnh đầu, 2 là đỉnh cuối
và 5 là trọng số của cạnh (1, 2).
Đối với đồ thị có hướng khơng có trọng số ta vẫn sử dụng cấu trúc dữ liệu như
đồ thị vô hướng khơng có trọng số, đồ thị có hướng và có trọng số ta sử dụng cấu
trúc dữ liệu như đồ thị vơ hướng có trọng số.
2

3


5

1

4

Hình 2.12. Đồ thị có hướng khơng có trọng số

Xét đồ thị có hướng khơng trọng số như đồ thị hình 2.13, chúng ta cũng biểu
diễn dưới dạng danh sách cạnh của nó là:

Đỉnh đầu

Đỉnh cuối


1

2

2

3

2

5

3


4

4

5

4

1

5

3

Và được lưu trữ trên tệp tin như sau:

Hình 2.13. Tệp số liệu đồ thị hình 2.13

Chúng ta sẽ xây dựng chương trình để đọc và hiển thị danh sách cạnh của đồ
thị được lưu trong tệp tin dothi213.inp như sau:
/* chương trình vidu22.cpp */
#include<stdio.h>
#include<conio.h>
#define MAX 20
typedef struct Canh
{
int dau, cuoi;
};
int n, m;

Canh E[MAX];
void doctep()
{
int d,c,ts;
FILE *F = fopen("dothi211.inp","rt");
if(F = = NULL) printf("\n Loi mo tep tin!");
else
{
fscanf(F,"%d %d\n",&n,&m);
for(int i = 1; i<= m;i++)
{

15


fscanf(F,"%d %d\n",&d,&c);
E[i].dau = d; E[i].cuoi = c;
}
}
fclose(F);
}
void hienthi()
{ int i;
printf("\nDo thi G co %d dinh va %d canh\n",n,m);
printf("\nSTT Dau Cuoi\n");
for(i = 1; i<= m; i++)
printf("%3d %3d %3d\n", (i+1), E[i].dau, E[i].cuoi);
}
void main()
{

clrscr();
doctep();
hienthi();
getch();
}

Hình 2.14. Chạy chương trình vidu22.cpp

2.
2.3.
3. BI
BIỂ
ỂU DIỄN Đ
ĐỒ
Ồ TH
THỊỊ BẰNG DANH SÁCH LÂN CẬN KỀ
Cho đồ thị G=(V, E), vơ hướng và khơng có trọng số như sau:
2

1

6

3

4

5

Hình 2.15. Đồ thị vơ hướng khơng có trọng số


Trong cách biểu diễn này mỗi đỉnh v tương ứng với một danh sách N(v) các
đỉnh kề với nó, tức là
N(v) = {w  V: (v, w)  E}, Ký hiệu N(x) thường được sử dụng
để nói lên lực lượng của đại lượng x.


Trong ví dụ thuộc hình 2.16 danh sách kề được mô tả như trong bảng dưới
đây.
Danh sách lân cận của các đỉnh trong đồ thị hình 2.16 là:
Đỉnh

Danh sách các đỉnh kề

1

2, 3, 6

2

1, 3, 4

3

1, 2, 4

4

2, 3, 5


5

4, 6

6

1, 5

Hình ảnh của mảng lưu trữ đồ thị hình 2.16 như sau:
DC[1]

DC[2]

DC[3]

DC[4]

DC[5]

DC[6]

2

1

1

2

4


1

3

3

2

3

6

5

6

4

4

5

Hình 2.16. Hình ảnh lưu trữ đồ thị trên hình 2.16
dưới dạng danh sách lân cận

Trong cách lưu trữ này, chúng ta thêm một số 0 vào cuối danh sách các đỉnh
kề của mỗi đỉnh trong đồ thị để đánh dấu hết đỉnh kề của đỉnh tương ứng, ví dụ
đỉnh 1 có các đỉnh kề là 2, 3, 6 thì ta thêm số 0 vào cuối để mỗi khi chương trình
đọc sẽ kiểm tra xem đã hết các đỉnh kề của đỉnh 1 chưa, thực chất của việc làm

này là do ta sử dụng tệp tin văn bản để lưu trữ, mà cách đọc của ngôn ngữ lập trình
C đối với tệp tin văn bản là đọc tuần tự đến hết tệp thì thơi chứ khơng đọc từng
khối như cách đọc tệp tin nhị phân.

17


Trong bảng này cho ta biết đỉnh 1 có các đỉnh kề là 2, 3 và 6; đỉnh 2 có các
đỉnh kề là 1, 3 và 4. Với cách biểu diễn này ta khai báo cấu trúc dữ liệu cho mỗi
đỉnh là một nút của danh sách liên kết đơn. Khai báo một mảng con trỏ các nút để
lưu các danh sách mà mỗi phần tử của mảng sẽ trỏ đến nút đầu tiên của các danh
sách liên kết này; danh sách thứ i lưu những đỉnh kề của đỉnh i.
typedef struct Dinh
{
int tendinh;
Dinh *next;
};
Dinh *DC[MAX]; // MAX = 100 là hằng số cho trước

Cấu trúc dữ liệu kiểu này được gọi là danh sách tổng quát. Chúng ta thấy rằng
trong ngơn ngữ lập trình C thì chỉ số của phần tử đầu tiên của mảng là 0, nhưng
chúng ta cũng có thể bắt đầu từ chỉ số là 1, trong trường hợp lấy chỉ số của mảng
bắt đầu là 1 thì chúng ta phải khai báo mảng có kích thước phù hợp với yêu cầu
của bài toán.
Đối với đồ thị vơ hướng có trọng số, đồ thị có hướng khơng trọng số và đồ thị
có hướng có trọng số thì chúng ta cũng có thể xây dựng cấu trúc dữ liệu kiểu danh
sách lân cận để lưu trữ và xử lý.
Sau đây chúng ta sẽ xây dựng chương trình nhập dữ liệu cho đồ thị từ tệp tin
và hiển thị danh sách lân cận, lưu đồ thị trong hình 2.16 và hình ảnh lưu trữ của nó
được minh hoạ trong hình 2.17, mảng DC sẽ lấy chỉ số 1 là phần tử đầu tiên của

mảng (cách lấy này để cho việc cài đặt và xử lý cho tự nhiên theo số hiệu các đỉnh
bởi vì ta lấy số hiệu đỉnh bắt đầu là 1). Vì đồ thị có n đỉnh, cho nên chúng ta sẽ có
n danh sách liên kết đơn, danh sách thứ i lưu các đỉnh kề của đỉnh thứ i trong đồ
thị, vì vậy chúng ta sẽ phải viết các hàm thao tác trên danh sách liên kết đơn như
hàm void themvaodanhsach(int x, Dinh **L): có tác dụng thêm một nút có nội
dung là x vào cuối danh sách liên kết đơn được quản lý bởi con trỏ L, hàm hiển thị
danh sách void hienthidanhsach(Dinh *L): dùng để hiển thị danh sách được quản
lý bởi con trỏ L.

Hình 2.17. Tệp tin dothi216.inp lưu trữ đồ thị trên hình 2.16


CH
CHƯƠNG
ƯƠNG 3- ĐƯỜNG ĐI NG
NGẮ
ẮN NH
NHẤ
ẤT
3.1.KHÁI N
NIIỆM VỀ ĐƯ
ĐƯỜNG
ỜNG ĐI V

À ĐƯỜNG ĐI NG
NGẮ
ẮN NHẤT
Trong thực tế cuộc sống, do thói quen người ta thường vẽ lên giấy những điểm
biểu thị cho các cá thể, các khu dân cư, các đơn vị hành chính, các nút giao
thơng…và nối các điểm đó với nhau bằng những nét vẽ hoặc những mũi tên đặc

trưng cho mối liên hệ nào đó. Các sơ đồ này dùng ở khắp mọi nơi với các tên gọi
khác nhau. Trong kinh tế gọi đó là sơ đồ tổ chức. Trong giao thơng vận tải gọi đó
là mạng giao thơng…Chính D.Konig là người đầu tiên đề nghị gọi các sơ đồ đó là
“đồ thị", đồng thời đề nghị nghiên cứu một cách có hệ thống các tính chất của nó.
Rất nhiều ngành khoa học khác nhau sử dụng những khái niệm định lý, hệ
quả, bổ đề…của Lý thuyết đồ thị để đưa vào xây dựng các ứng dụng trong ngành
của mình. Điều này càng chứng tỏ “Lý thuyết đồ thị" có rất nhiều ứng dụng trong
xã hội. Để có thể áp dụng vào các lĩnh vực khác nhau, Lý thuyết đồ thị đã được
hình thức hố với nhiều khái niệm, định lý được định nghĩa một cách trừu tượng
nhưng vẫn giữ được mối quan hệ với những đồ thị thực tế. Trong chương này
chúng ta cũng sẽ nghiên cứu một số thuật tốn tìm đường đi ngắn nhất trên đồ thị.
Cho đồ thị vơ hướng, liên thơng, có trọng số G = (V, E).
f: E → R+ và đỉnh uV. Đường đi của từ đỉnh u đến đỉnh v được thể hiện bằng:
u = e1, e2,..,em = v
hay u = (u1, u2), (u2, u3),…(ui−1, ui),..,(un−1, un), (un, v) và
n

m

i =1

i =1

 =  f (ei ) =  f (ui .ui +1 )
 là tổng trọng số của các cạnh trên đường đi. Với mọi x  V, hãy tìm đường
đi *(u, x) ngắn nhất nối u với x. Chúng ta có hai bài tốn cần giải quyết, bài tốn
một là tìm xem cần đi qua số cạnh là ít nhất để đi được từ u đến v, bài tốn hai là
cần tìm đường đi ngắn nhất (khơng quan tâm đến số cung đi qua) để đi được từ u
đến v mà chỉ quan tâm đến độ dài đường đi (độ dài đường đi được tính bằng đơn
vị đo chiều dài). Để giải hai bài toán này chúng ta sẽ nghiên cứu hai thuật toán

“thuật toán gán nhãn đồ thị” và “thuật toán Dijkstra”.

19


3.2.THUẬT TỐN GÁN NHÃN ĐỒ THỊ GIẢI BÀI TỐN 1

Hình 3.1. Đồ thị liên thơng G liên thơng khơng có tr ọng số

Tư tưởng của thuật tốn gán nhãn(u,v): tìm đường đi ngắn nhất từ u đến v như
sau:
+ Trước tiên cho lớp các đỉnh có nhãn là m = 0 gồm đỉnh u
lớp A0
+ Tìm các đỉnh liên thơng với từng đỉnh của lớp Am; rồi tăng m lên và gán
nhãn là m;
+ Tiếp tục tìm cho đến khi việc gán nhãn cho đỉnh v thì dừng lại.
Ví dụ sau tìm đường đi ngắn nhất từ đỉnh 1 đến 7.

Hình 3.2. Gán nhãn đỉnh 1 là 0

Thực hiện gán nhãn cho các đỉnh kề của đỉnh 1 là m+1.


Hình 3.3. Gán nhãn t ất cả các đỉnh kề của đỉnh 1

Hình 3.4. Gán nhãn t ất cả các đỉnh kề của đỉnh 2, 4, và 5

Hình 3.5. Gán nhãn t ất cả các đỉnh kề của đỉnh 3, 10, 8 và 2

21



Đến lúc này đỉnh 7 đã được gán nhãn, thuật tốn kết thúc kể cả khi cịn nhiều
đỉnh chưa được gán nhãn.
Thuật toán gán nhãn đồ thị được cài đặt tựa ngôn ngữ C, chúng ta sẽ coi các
đỉnh được đánh theo thứ tự 1, 2,…, n.
Bước 1. Khởi tạo
− Gán tất cả các đỉnh có nhãn là −1
− Gán cho đỉnh 1 có nhãn là m = 0
M = 0; // là số cạnh đi từ u đến v
// lớp các đỉnh có nhãn là m
// là 1 đỉnh u
Am = {u};

ban

đầu

được

gán

Bước 2. Gán nhãn các đỉnh
while(v chưa có nhãn) // tức là nhãn(v) = −1
{
2.1. Am+1 =[ ];
//Tập các đỉnh có nhãn là m+1 là rỗng (chưa đi đến)
2.2. for all x  Am
// tất cả các đỉnh có nhãn là m
for all y  V+(x)

if(y chưa có nhãn)
+ Gán nhãn cho y = m+1;
+ Am+1 = Am+1  y;
// thêm y vào tập các đỉnh có nhãn là m+1
}

Bước 3. Chỉ ra đường đi từ đỉnh u đến đỉnh v
Trước hết ta sẽ khai báo mảng DD − đường đi, để lưu vị trí của các đỉnh trên
đường đi.
DD[m]: = v;

Đỉnh thứ, đỉnh cuối cùng, lưu trên các đỉnh của đường đi theo thứ từ từ đỉnh v
ngược lên u, đi ngược lại từ đỉnh v để tìm các đỉnh kế trước đỉnh hiện tại
for(i = m−
− 1; i >= 0; i− −
−) // Tìm các đỉnh kề trước
{
for (j = 1;j<= n; j++)
if((Nhan[j] = i) && (A[j,v] = 1)) DD [i]: = j;
}


− Bước 4. Hiển thị đường đi trong DD;
printf('Duong di tu dinh ', u,' den dinh ',v);
for (i = 0; i< m; i++) printf(DD [i]:4);

Chương trình tìm đường đi ngắn nhất bằng thuật tốn Gán nhãn đồ thị

Hình 3.6. Tệp số liệu của đồ thị 5.1


/* Chương trình vidu51.cpp */
#include<stdio.h>
#include<conio.h>
#define MAX 20
int n, A[MAX][MAX];
int nhan[MAX];
int DD [MAX];
void doctep()
{
int x;
FILE *F = fopen("dothi51.inp","rt");
if(F = = NULL)
printf("\n Loi doc tep tin !");
else
{
fscanf(F,"%d\n",&n); printf("\n n = %d",n);
for(int i = 1;i<= n;i++)
{
printf("\n");
for(int j = 1;j<= n;j++)
{
fscanf(F,"%d",&x);
A[i][j] = x;
printf("%3d",A[i][j]);
}
}
}
fclose(F);
}
void gannhan(int u, int v)

{
int i,j,k,m,x,y;

23


for(i = 1;i<= n;i++) nhan[i] = −1;
m = 0; nhan[u] = m;
//gán nhãn
while(nhan[v] == −1)
{
for(x = 1;x<= n;x++)
if(nhan[x] == m)
for(y = 1;y<= n;y++)
if
((nhan[y]
==
−1)&&(A[x][y]
nhan[y] = m+1;
m++;
}
//In đường đi
k = v;
DD [m] = v;
for(i = m;i>= 0;i−−)
{
for(j = 1;j<= n;j++)
if((nhan[j]!
=
nhan[k])

&&
(nhan[j]
&& (A[j][k] == 1))
{
DD[i] = j; k = j;
}
}
printf("\n Duong di: ");
for(i = 0;i<= m;i++)
printf(" %3d", DD [i]);
}
void main()
{
clrscr();
doctep();
gannhan(1,7);
getch();
}

Hình 3.7. Kết quả chạy chương trình vidu51.cpp

==

==

1))

i)



3.3.THUẬT TỐN DIJKSTRA GIẢI BÀI TỐN 2

Cho đồ thị có hướng, liên thơng, có trọng số G = (V, E),
f: E → R+, và hai đỉnh u, v  V. Hãy tìm đường đi *(u, v) sao cho độ dài đường
đi từ đỉnh u đến đỉnh v là ngắn nhất.
Ký hiệu T(u, v) là tập hợp các đường đi nối u với v trong đồ thị G và công
thức sau:
 (*) = min {() : T}
Năm 1959 Edsger W. Dijkstra đưa ra một thuật toán rất hiệu quả để giải bài
toán đường đi ngắn nhất. Thuật toán thực hiện việc gán và giảm giá trị của nhãn
tại mỗi đỉnh của đồ thị G.
Chúng ta sẽ dùng thuật toán Dijkstra để giải quyết bài toán này. Độ dài đường
đi *(u, v) từ đỉnh u đến đỉnh v là ngắn nhất trong tất cả các đường đi từ u đến v.
Sau đây chúng ta sẽ xem xét và tìm hiểu tư tưởng của thuật tốn này, với đồ thị
hình 5.8, chúng ta cần tìm đường đi *(2, 4) từ đỉnh 2 đến đỉnh 4 có độ dài là ngắn
nhất.

Hình 3.8. Đồ thị G có hướng, liên thơng và có trọng số

+ Sử dụng phương pháp tham an và sử dụng kỹ thuật gán nhãn đồ thị; phương
pháp tham ăn ở đây là thực hiện gán nhãn cho các đỉnh kề với đỉnh hiện tại trên
đường đi.
+ Sử dụng tập S để lưu các đỉnh được chọn trên đường đi từ
u đến v.
+ V\S là tập những đỉnh thuộc V nhưng không thuộc S.
Thuật tốn tìm đường đi ngắn nhất – Dijkstra
Bước 1.Khởi tạo
a, Gán nhãn đỉnh u là 0.
b, Tập là S rỗng
25



×