Đường đi ngắn nhất trong ĐT có trọng số - iChooseFish.com

33
Đường đi ngắn nhất trong ĐT trọng số

Transcript of Đường đi ngắn nhất trong ĐT có trọng số - iChooseFish.com

Đường đi ngắn nhất trong ĐT có trọng số

Nội dung

Giới thiệu

Thuật toán

Ford-Bellman

Dijsktra

Floyd

Giới thiệu

Bài toán

Cho G = <V, E>. Mỗi cạnh của đồ thị được gán với

một số thực gọi là trọng số.

Bài toán: s và t là 2 đỉnh của đồ thị G . Hãy tìm đường

đi có tổng trọng số nhỏ nhất từ s đến t.

A

B

C

D

E F

G

5

3

916

22

5

3

15

17

711

Đường đi ngắn nhất từA đến D?

Ma trận trọng số

Xét đồ thị G = (V, E) với tập đỉnh V = {v1, …, vn}.

Mỗi cạnh của đồ thị được gán với một số thực gọi là

trọng số

Ma trận kề của đồ thị là ma trận Anxn xác định như sau:

𝑎𝑖𝑗 = 0 nế𝑢 𝑣𝑖𝑣𝑗 ∉ 𝐸

𝑐 nếu 𝑣𝑖𝑣𝑗 ∈ 𝐸, trọng số bằng c

Điều kiện

Để bài toán có lời giải:

Phải tồn tại đường đi từ s tới t

Đồ thị vô hướng liên thông hoặc đồ thị có hướng liên

thông mạnh

Đồ thị vô hướng, trong đó s, t thuộc một thành phần liên

thông

Đồ thị có hướng có đường đi từ s tới t

Đồ thị không chứa chu trình âm

Đồ thị vô hướng không có cạnh âm

Đồ thị có hướng không có chu trình âm

Ví dụ

Ví dụ: đường đi ngắn nhất từ A đến C?

A

B

C

D

E F

G

5

3

916

22

5

3

15

17

7-5

Ví dụ

Ví dụ: đường đi ngắn nhất từ A đến C?

A

B

C

D

E F

G

5

3

916

22

5

3

15

17

7-5

Ý tưởng

Nếu s, u2, …, uk-1, v, uk+1, …, un-1, t là đường đi ngắn

nhất từ s → t thì:

s, u2, …, uk-1, v là đường đi ngắn nhất từ s → v

v, uk+1, …, un-1, t là đường đi ngắn nhất từ v → t

⇒ mở rộng thành bài toán tìm đường đi ngắn nhất từ một

đỉnh đến tất cả các đỉnh còn lại

… …s v t

…X

Ý tưởng

Tại đỉnh cần xét, ta thử đường đi qua các đỉnh trung

gian để đến đích

Cập nhật đường đi ngắn nhất nếu tìm được đường đi

tốt hơn đường đi tốt nhất đã biết.

Thông tin cần lưu:

Độ dài đường đi ngắn nhất từ s → v đã biết

Đỉnh nằm trước v trên đường đi ngắn nhất đã biết.

Thuật toán

Thuật toán Ford-Bellman

// Khởi tạo

for v V do{

d[v]:= a[s,v]; // khoảng cách từ s v = trọng số cung

π[v]:= s; // đỉnh trước v trên đường đi là s

}

d[s]:= 0;

// Lặp

for k:= 1 to |V|-2 do

for v V\{ s} do

for u V do

if d[v] > d[u] + a[u,v] then{

d[v]:= d[u] + a[u,v];

π[v]:= u;

}

Ví dụ: đường đi min từ z

Đồ thị:

0

z

u v

x y

6

5

–3

9

7

7

8

–2

–4

2

Ví dụ

Khởi tạo

0

7

6

z

u v

x y

6

5

–3

9

7

7

8

–2

–4

2

i d[z];π[z] d[u]; π[u] d[v];π[v] d[y];π[y] d[x];π[x]

0; z 6; z ∞; z ∞; z 7; z

Ví dụ

0

27

46

z

u v

x y

6

5

–3

9

7

7

8

–2

–42

i = 1

i d[z];π[z] d[u]; π[u] d[v];π[v] d[y];π[y] d[x];π[x]

0; z 6; z ∞; z ∞; z 7; z

1 0; z 6; z 4; x 2; u 7; z

Qua u v y X

u 6, z 11, u 2, u 7, z

v 9 6, z 11, u 2, u 7, z

y 6, z 9, y 2, u 7, z

x 6, z 4, x 2, u 7, z

Ví dụ

0

27

46

z

u v

x y

6

5

–3

9

7

7

8

–2

–42

i = 2

i d[z];π[z] d[u]; π[u] d[v];π[v] d[y];π[y] d[x];π[x]

0; z 6; z ∞; z ∞; z 7; z

1 0; z 6; z 4; x 2; u 7; z

2 0; z 2; v 4; x 2; u 7; z

Qua u v y x

u 6, z 4, x 2, u 7, z

v 2, v 4, x 2, u 7, z

y 2, v 4, x 2, u 7, z

x 2, v 4, x 2, u 7, z

Ví dụ

0

27

46

z

u v

x y

6

5

–3

9

7

7

8

–2

–42

i = 3

I d[z];π[z] d[u]; π[u] d[v];π[v] d[y];π[y] d[x];π[x]

0; z 6; z ∞; z ∞; z 7; z

1 0; z 6; z 4; x 2; u 7; z

2 0; z 2; v 4; x 2; u 7; z

3 0; z 2; v 4; x -2; u 7; z

Qua u v y x

u 2; v 4, x -2, u 7, z

v 2, v 4, x -2, u 7, z

y 2, v 4, x -2, u 7, z

x 2, v 4, x -2, u 7, z

Nhận xét

Thuật toán Ford-Bellman áp dụng được cho trường

hợp không có chu trình âm trong đồ thị

Nhược điểm:

Chi phí tính toán lớn

Không thể cải tiến cho trường hợp tổng quát

Các vòng lặp thường hội tụ về kết quả sớm hơn so với

điều kiện dừng vòng lặp

Nếu đồ thị không có cạnh âm thì: giá trị nhỏ nhất của

d[i] trên mỗi hàng của ma trận F-B sẽ không thể nhỏ

hơn tính từ hàng đó về sau

Thuật toán Dijkstra

Ý tưởng:

Do đồ thị không có cạnh âm: trong mỗi bước, đỉnh có

khoảng cách nhỏ nhất (d[v] min) sẽ không thay đổi về

sau

Chọn đỉnh này là đỉnh trung gian đi đến các đỉnh còn lại

sẽ giúp đường đi có khả năng tối ưu cao hơn

Thuật toán Dijkstra// Khởi tạo

for v V do{

d[v]:= a[s,v];

π[v]:= s;

}

d[s]:= 0; T:= V\{s} ; // T là tập các đỉnh còn có thể rút ngắn đường đi

// Lặp

while T != do {

u := ;

T:= T\{u} ;

for v T do

if d[v] > d[u] + a[u,v] then{

d[v]:= d[u] + a[u,v];

π[v]:= u;

}

}

T) t td(minargt

Ví dụ

0

z

u v

x y

6

5

–3

9

7

7

8

–2

–4

2

Tìm đường đi ngắn nhất từ z đến các đỉnh còn lại

Ví dụ

0

7

6

z

u v

x y

6

5

3

9

2

7

8

2

12

Khởi tạo

i d[z];π[z] d[u]; π[u] d[v];π[v] d[y];π[y] d[x];π[x]

0; z 6; z ∞; z ∞; z 7; z

Ví dụ

Bước lặp 1

i d[z];π[z] d[u]; π[u] d[v];π[v] d[y];π[y] d[x];π[x]

0; z 6; z ∞; z ∞; z 7; z

1 - - 11; u 7; u 7; z

0

77

116

z

u v

x y

6

5

3

9

2

7

8

2

12

Ví dụ

Bước lặp 2

i d[z];π[z] d[u]; π[u] d[v];π[v] d[y];π[y] d[x];π[x]

0; z 6; z ∞; z ∞; z 7; z

1 - - 11; u 7; u 7; z

2 - - 11; u - 7; z

0

77

116

z

u v

x y

6

5

3

9

5

7

8

2

12

Ví dụ

Bước lặp 3

i d[z];π[z] d[u]; π[u] d[v];π[v] d[y];π[y] d[x];π[x]

0; z 6; z ∞; z ∞; z 7; z

1 - - 11; u 7; u 7; z

2 - - 11; u - 7; z

3 - - 10; x - -

0

7

6

z

u v

x y

6

5

3

9

5

7

8

2

12

Thuật toán Floyd

Đường đi ngắn nhất giữa tất cả các cặp đỉnh?

Thuật toán Floyd dựa trên ý tưởng:

Tất cả các đường đi con của đường đi ngắn nhất là ngắn

nhất

Giả sử ma trận D = [dij](k) là đường đi ngắn nhất từ i đến j

chỉ đi qua các đỉnh trung gian 1, 2, …, k

=> Kết quả của bài toán sẽ là [dij](n)

Thuật toán Floyd

Xác định dij(k):

dij(0) = a[i, j]

k > 0:

Thuật toán Floyd

Xác định dij(k):

dij(0) = a[i, j]

k > 0:

dij(k) = min (dij

(k-1); dik(k-1) + dkj

(k-1))

Thuật toán Floyd

Xác định đường đi bằng ma trân đỉnh trước cuối của

đường đi

π[i, j] = Đỉnh cuối cùng trên đường đi ngắn nhất từ i

đến j

Khởi tạo: π[i, j] = I

Tại mỗi bước lặp: xác định xem dùng đỉnh k có làm rút

ngắn đường đi từ i đến j không?

Nếu có:

Lưu lại trọng số của đường đi mới – ngắn hơn – từ i đến j

Lưu lại thông tin về việc thay đổi đường đi để đi qua k

Thuật toán Floyd

Lưu lại thông tin về việc thay đổi đường đi để đi qua k

=> π[i, j] = ?

Thuật toán Floyd Lưu lại thông tin về việc thay đổi đường đi để đi qua k

=> π[i, j] = π[k, j]

Thay đổi thông tin:

If (d[i, j] > d[i, k] + d[k, j]) then

Begin

d[i, j]:= d[i, k] + d[k, j];

π[i, j]:= π[k, j];

End

Thuật toán Floyd// Khởi tạo

For i:= 1 to n do

For j:= 1 to n do

Begin

d[i, j]:= a[i, j]; π[i, j]:= i;

End;

// Bước lặp

For i:= 1 to n do

For i:= 1 to n do

For j:= 1 to n do

If (d[i, j] > d[i, k] + d[k, j]) then

Begin

d[i, j]:= d[i, k] + d[k, j];

π[i,j]:= π[k,j];

End;

Ví dụ

Tìm đường đi ngắn nhất giữa tất cả các cặp đỉnh trong

đồ thị: