You are on page 1of 17

Mô phỏng thuật toán Dijkstra

TRƯỜNG ĐẠI HỌC BÁCH KHOA HÀ NỘI


KHOA TOÁN TIN ỨNG DỤNG
----- -----

TIỂU LUẬN
Đề tài: Lập trình tính toán mô phỏng thuật toán
tìm đường đi ngắn nhất theo thuật toán dijkstra

Giáo viên hướng dẫn: Nguyễn Hữu Điển


Sinh viên thực hiện : Lê Văn Cường & Nguyễn Thị Hòa
Lớp: toán 2-k51.

Hà Nội, tháng 11 năm 2009

-1-
Giảng viên: Thầy giáo Nguyễn Hữu Điển
Sinh viên thực hiện: Lê Văn Cường & Nguyễn Thị Hòa
Mô phỏng thuật toán Dijkstra

PHẦN A: LÝ THUYẾT CƠ SỞ

1. Giới thiệu

1.1. Hiện trạng và vấn đề đặt ra

Vài thập kỉ trở lại đây cả thế giới đang chứng kiến sự phát triển bùng
nổ của công nghệ thông tin với một tốc độ chóng mặt. Kèm theo đó đang
xảy ra một xu hướng tạm gọi là “tin học hóa toàn thể”, khi mà công nghệ
thông tin đã và đang xâm nhập vào tất cả các lĩnh vực: kinh tế, quân sự,
khoa học, đời sống…

Có một thực tế là học sinh và cả sinh viên đang ngày càng nhàm chán
hơn với cách dạy và học truyền thống. Rõ ràng là Toán, Lý, Hóa và cả các
môn khác nữa sẽ dễ vô hơn nếu người học nhìn thấy được những minh họa
sinh động rõ ràng và dễ hiểu. Đồng thời không phải lặp đi lặp lại một cách
thật nhàm chán các tính toán hay các phép biến đổi nặng nề mà không hiểu
được bản chất thật sự.

Hiện nay ở Việt Nam chúng ta đã có những phần mềm nổi tiếng hỗ
trợ giáo viên, học sinh, sinh viên trong giảng dạy và học tập, như Maple,
Matlab, Mathematica, Mathcad…. Tuy nhiên nổi tiếng hơn cả và được rất
nhiều người sử dụng là Maple. Thậm chí các viện đại học trên thế giới
đang thay đổi dần cách học toán, hay chí ít cũng phát triển song hành thêm
một phương pháp mới học toán đại học bên cạnh cách học truyền thống:
Dạy cho sinh viên học sinh cách giải toán bằng Maple. Bản thân nhóm khi
tìm hiểu Maple cũng nhận thấy đây là một phần mềm tính toán rất thuận
tiện cho học tập và sử dụng.

1.2. Maple là gì?

Maple là một chương trình tính toán mạnh mẽ. Hãy thử làm một phép
so sánh nhỏ với một công cụ tính toán thật quen thuộc với chúng ta: Chiếc
máy tính bỏ túi (một phép so sánh rất khập khiễng). Máy tính bỏ túi thì chỉ
có thể tính toán với số cụ thể nhưng Maple thì khác. Nó có khả năng làm

-2-
Giảng viên: Thầy giáo Nguyễn Hữu Điển
Sinh viên thực hiện: Lê Văn Cường & Nguyễn Thị Hòa
Mô phỏng thuật toán Dijkstra

việc với cả những biểu thức toán học và các phép tính hình thức. Từ rút
gọn, khai triển biểu thức, tính giới hạn, đạo hàm, nguyên hàm (chứ không
phải chỉ là tính tích phân) ở bậc phổ thông. Đến khai triển Taylor, tìm
nghiệm phương trình vi phân, tính định thức, giải hệ phương trình tuyến
tính có tham số… Maple xử lý trong tích tắc!

Không chỉ như vậy, Maple còn thể hiện tài năng ở khả năng minh hoạ
xuất sắc đồ thị hai chiều lẫn mặt cong trong không gian ba chiều, đồ thị toạ
độ cực, tham số, hàm ẩn. Điểm nổi bật hơn, khả năng cho hình chạy sống
động làm cho việc học tập và giảng dạy trở nên rất thú vị.

Đặc điểm:

• Là một hệ thống tính toán trên các ký hiệu và biểu thức toán học.
• Có thể thực hiện hầu hết các phép toán cơ bản của chương trình toán
đại học và sau đại học.Tính toán được nghiệm chính xác và gần đúng của
một lớp rộng các bài toán lý thuyết và ứng dụng.
• Cung cấp các công cụ minh họa hình học thuận tiện bao gồm: đồ thị,
hình vẽ tĩnh và động của các đường và mặt được cho bởi các hàm tùy ý trong
nhiều hệ tọa độ khác nhau.
• Một ngôn ngữ lập trình đơn giản và mạnh mẽ có khả năng chuyển đổi
sang các ngôn ngữ lập trình khác.
• Cho phép trích xuất dữ liệu ra các định dạng khác nhau như Latex,
Word, HTML...
• Một công cụ biên soạn giáo trình điện tử và trình diễn bài giảng thuận
tiện.
• Hỗ trợ theo nhiều mức độ cho sinh viên trong việc học tập.

1.3. Cấu trúc tập hợp và danh sách trong Maple

Tập hợp của Maple được viết như một dẫy bao quanh bởi dấu { }, đây là
ký hiệu toán học cho tập hợp hữu hạn. Cũng như các đối tượng khác của
Maple tập hợp được gán giá trị như một biến, có thể làm đối số, kết quả của
phép tính hoặc một hàm.Maple cung cấp một số toán tử như lấy hợp, lấy
giao và hiệu trên tập hợp.

-3-
Giảng viên: Thầy giáo Nguyễn Hữu Điển
Sinh viên thực hiện: Lê Văn Cường & Nguyễn Thị Hòa
Mô phỏng thuật toán Dijkstra

Bảng 1.7: Toán tử tập hợp trong Maple


Tên toán tử Toán tử Ví dụ
Maple >set1:={a,b};
set1:={a,b}
>set2:={a,d,e};
set2:={a,d,e}
>set3:={b,e};
set3:={b,e}

Hợp a∪b >u:=set1 union set2;


a union b u:={b,a,d,e}
a∩b >i:=set1 intersect set2;
a intersect b i:={e}
Trừ tập hợp a-b >d:=set1 minus set3;
a minus b d:={a}

Việc sắp xếp thứ tự trong tập hợp không có qui tắc nào đưa ra, chúng
ta cố gắng sắp xếp dữ liệu khi đưa vào thì tập hợp sẽ dữ nguyên thứ tự đó.

Danh sách của Maple là một dẫy nhưng trong nó không có phần tử
lặp lại (mỗi phần tử là duy nhất). Những phần tử trùng nhau trong danh sách
sẽ bị loại bỏ chỉ để lại một. Danh sách không có toán tử hợp, giao và trừ.
Danh sách của Maple tạo ra bởi dẫy nằm trong dấu [ và ]. Phân biệt dẫy và
danh sách: khi viết [a,b],[b,c] thì Maple hiểu là hai danh sách , còn khi viết
(a,b),(b,c) thì chỉ là một dẫy mà thôi a,b,b,c.

1.4 Vẽ đồ thị hàm số

1.4.1. Hàm một biến,đồ thị 2D - Lệnh plot

> plot(cos(x) + sin(x), x=-Pi..Pi);

-4-
Giảng viên: Thầy giáo Nguyễn Hữu Điển
Sinh viên thực hiện: Lê Văn Cường & Nguyễn Thị Hòa
Mô phỏng thuật toán Dijkstra

¾ plot(sin(t),t);

(Khi không chỉ ra miền xác định, Maple sẽ lấy miền mặc định là [-10,10])
¾ plot(tan(x),x=-2*Pi..2*Pi,y=-4..4);

-5-
Giảng viên: Thầy giáo Nguyễn Hữu Điển
Sinh viên thực hiện: Lê Văn Cường & Nguyễn Thị Hòa
Mô phỏng thuật toán Dijkstra

(Chỉ ra cả miền xác định và miền giá trị)


> plot([sin(x), x-x^3/6], x=0..2, color=[red,blue],
style=[point,line]);
(Vẽ đồ thị nhiều tham số. Danh sách các hàm số để trong cặp ngoặc vuông,
tham số color chỉ ra thứ tự màu sắc cho từng đồ thị, tham số style chỉ ra kiểu
nét vẽ theo thứ tự cho các đồ thị).

-6-
Giảng viên: Thầy giáo Nguyễn Hữu Điển
Sinh viên thực hiện: Lê Văn Cường & Nguyễn Thị Hòa
Mô phỏng thuật toán Dijkstra

1.4.2. Hàm 2 biến,đồ thị 3D - Lệnh plot 3D

> plot3d(sin(x*y),x=-Pi..Pi,y=-1..1);

> c1:= [cos(u)-2*cos(0.4*v),sin(u)-2*sin(0.4*v),v];


> c2:= [cos(u)+2*cos(0.4*v),sin(u)+2*sin(0.4*v),v];
> c3:= [cos(u)+2*sin(0.4*v),sin(u)-2*cos(0.4*v),v];
>
plot3d({c1,c2,c3},u=0..2*Pi,v=0..10,grid=[25,15]);

-7-
Giảng viên: Thầy giáo Nguyễn Hữu Điển
Sinh viên thực hiện: Lê Văn Cường & Nguyễn Thị Hòa
Mô phỏng thuật toán Dijkstra

(Vẽ nhiều mặt cong cùng nhau: {c1, c2, c3}, ở đây c1, c2, c3 được mô tả
dưới dạng tham số {u,v})
1.4.3. Vẽ tiếp tuyến - Lệnh showtangent

> with(student):
> showtangent(x^2+5, x = 2);

1.4.4. Vẽ đồ thị kèm biểu đồ - Lệnh rightbox, leftbox, middlebox

> with (student):


> rightbox(sin(x)*x+sin(x), x=0..2*Pi, 4,
color=CYAN);

-8-
Giảng viên: Thầy giáo Nguyễn Hữu Điển
Sinh viên thực hiện: Lê Văn Cường & Nguyễn Thị Hòa
Mô phỏng thuật toán Dijkstra

1.5. Một số lệnh

1.5.1. Cấu trúc điều khiển

a. Câu lệnh rẽ nhánh

if conditional expression then statement sequence


elif conditional expression then statement sequence
else statement sequence
fi
Ví dụ:
> a := 3; b := 5;
a := 3
b := 5
> if (a > b) then a else b fi;
5

b. Lặp xác định

for <name> from <expr> to <expr> do <statement sequence> od;


hoặc

-9-
Giảng viên: Thầy giáo Nguyễn Hữu Điển
Sinh viên thực hiện: Lê Văn Cường & Nguyễn Thị Hòa
Mô phỏng thuật toán Dijkstra

for <name> in <expr> do <statement sequence> od;


Ví dụ 1:
> sum := 0;
> for i from 11 to 100 do
sum := sum + i
> od;
> print(sum);
Ví d_ 2:
> bob:=[1,2,4,5,7];
> sum:=0;
> for m in bob do
> sum:=sum+m
> od;
> print(sum);
Ví d_ 3:
> for i from 6 by 2 to 100 do print(i) od;

c. Lặp không xác định

while <expr> do <statement> od;

1.5.2 . Hàm và thủ tục

> p:= proc(x,y) if x^2 < y then cos(x*y) else


x*sin(x*y) fi
end:
> h:= proc(x) x^2 end:
> plot3d(p,-2..2,-1..h);

PHẦN B: MÔ PHỎNG THUẬT TOÁN TÌM ĐƯỜNG ĐI


NGẮN NHẤT

1. Giới thiệu bài toán

Bài toán tìm đường đi ngắn nhất là tìm đường đi trong một đồ thị
có trọng số (chiều dài) nối 2 đỉnh x và y đã cho trước với đặt tính là tổng
các trọng số của tất cả các cạnh là nhỏ nhất trong tất cả các đường đi từ
đỉnh x đến đỉnh y.

- 10 -
Giảng viên: Thầy giáo Nguyễn Hữu Điển
Sinh viên thực hiện: Lê Văn Cường & Nguyễn Thị Hòa
Mô phỏng thuật toán Dijkstra

Nguyên lý tối ưu là nếu tồn tại một đường đi ngắn nhất từ đỉnh I
đến đỉnh j và đỉnh k nằm trên con đường đi này thì ta phải có các đường
đi từ đỉnh i đến đỉnh k và đường đi từ đỉnh k đến đỉnh j là những đuờng
đi ngắn nhất.

Trong các giải thuật sau, ta dùng ma trận chiều dài L để chứa chiều
dài các cung, chiều dài cung là một số không âm (lớn hơn hay bằng 0) ta
có:
L[l,j]:=0 với mọi i=1,2..n
L[l,j]:>0 nếu tồn tại một cung từ đỉnh i đến đỉnh j
L[i,j]= vô cực nếu không tồn tại một cung từ đỉnh i đến đỉnh j

2. Giải thuật Dijstra

Gọi Q là hợp chứa các đỉnh chưa được chọn và S là tập hợp các
đỉnh đã được chọn.

Tại mỗi thời điểm , tập S chứa tất cả các đỉnh mà khoảng cách nhỏ
nhất từ X đến chúng được xác định. Tập Q chứa các đỉnh còn lại.

Bắt đầu giải thuật với tập S chỉ chứa một đỉnh nguồn, khi giải thuật
kết thúc thì tập S chứa tất cả các đỉnh của đồ thị và bài toán được giải
quyết xong. Tại mỗi bước, ta chọn một đỉnh của tập Q mà khoảng cách từ
đỉnh nguồn đến đỉnh này là nhỏ nhất và đưa đỉnh này vào tập S.

Đây là giải thuật tìm đuờng đi ngắn nhất của đồ thị có trọng
số(chiều dài) nối hai đỉnh X và Y đã cho trước với đặt tính là tổng các
trọng số của tất cả các cạnh là nhỏ nhất trong tất cả các đường đi từ đỉnh
X đến đỉnh Y .

Nếu tất cả đều bằng 1 thì bài toán này trở thành bài toán tìm đường
đi có số cạnh ít nhất nối giữa hai đỉnh X và Y.

Trong trường hợp tổng quát, đường đi từ đỉnh X đến đỉnh Y có thể
đi qua tất cả các đỉnh trong đồ thị, vì thế ta thường xét bài toán tìm đường
đi ngắn nhất nối từ đỉnh X cho trước với tất cả các đỉnh khác trong đồ thị.

- 11 -
Giảng viên: Thầy giáo Nguyễn Hữu Điển
Sinh viên thực hiện: Lê Văn Cường & Nguyễn Thị Hòa
Mô phỏng thuật toán Dijkstra

Như vậy, đuờng đi từ đỉnh nguồn một đỉnh khác là riêng biệt nếu
tất cả các đỉnh trung gian trên đường đi này đều nằm trong tập hợp S. Tại
mỗi bước của giải thuật, một mảng chiều dài K(gồm n phần tử) dùng để
chứa chiều dài đường đi riêng biệt ngắn nhất đến mỗi đỉnh của đồ thị.
Mỗi lần ta đưa đỉnh mới v vào tập hợp S, đường đi riêng biệt ngắn nhất
đến đỉnh v cũng là đường đi ngắn nhất trong tất cả các đường đi đến đỉnh
v. Khi giải thuật kết thúc tất cả các đỉnh nằm trên đồ thị đều nằm trong
tập hợp S, do đó tất cả các đường đi từ đỉnh nguồn đến tất cả các đỉnh
khác đều là đường đi riêng biệt.

3. Chương trình hoạt động như sau

3.1, Xây dựng hàm dijkstra theo giải thuật trên

CODE:

>restart:
with(networks):
dijkstra:=proc(G::graph, x)
local weight,L,K,P,Q,v,u:
weight:=proc(G::graph, u, v)
if edges({u,v},G)={} then
return infinity:
else
return eweight(edges({u,v},G)[1],G):
fi:
end;

P:={}:
Q:=vertices(G):
L:=table():
K:=table():
for v in vertices(G) do
L[v]:=infinity:
od:
L[x]:=0:
u:=x:

- 12 -
Giảng viên: Thầy giáo Nguyễn Hữu Điển
Sinh viên thực hiện: Lê Văn Cường & Nguyễn Thị Hòa
Mô phỏng thuật toán Dijkstra

while L[u]<infinity do
P:=P union {u}:
Q:=Q minus {u}:
if Q={} then
break:
fi:

# Cap nhat trong so tren cac dinh tam thoi


# cap nhat duong di ngan nhat tu x den v
for v in Q do
if L[u]+weight(G,u,v) < L[v] then
L[v]:=L[u]+weight(G,u,v):
K[v]:=u:
fi:
od:

# Tim 1 dinh voi khoang cach tam thoi ngan nhat tu x


u:=Q[1]:
for v in Q do
if L[v]<L[u] then
u:=v:
fi:
od:
# u la dinh tiep theo gan nhat voi x
od:
return [L,K];
end;

- 13 -
Giảng viên: Thầy giáo Nguyễn Hữu Điển
Sinh viên thực hiện: Lê Văn Cường & Nguyễn Thị Hòa
Mô phỏng thuật toán Dijkstra

3.2, Hàm đưa ra đường đi ngắn nhất giữa 2 dỉnh u và v

CODE:

>listpath:=proc(lk,u,v)
local p:

if lk[1][v]=infinity then
print("Khong tim thay duong di tu %1 to %2.", u, v):
fi:

if u=v then
return [u]:
else
return [listpath(lk,u,lk[2][v])[],v]:
fi:
end;

- 14 -
Giảng viên: Thầy giáo Nguyễn Hữu Điển
Sinh viên thực hiện: Lê Văn Cường & Nguyễn Thị Hòa
Mô phỏng thuật toán Dijkstra

3.3,Các đỉnh trong đồ thị


Khai báo các đỉnh trong đồ thị, biến sẽ được truyền lên hàm dijkstra

CODE:

>dothi:=graph({A, B, C, D, E, F, G, H, I, S},{{A,D}, {A,G}, {B,G}, {B,I},


{C,D}, {C,E}, {A,S}, {D,F}, {E,F}, {E,H}, {F,G}, {F,I}, {H,I}, {B,S}}):

3.4, Nhập trọng số giữa các đỉnh


Sau khi khai báo các đỉnh trong đồ thị, ta dùng hàm eweight để
nhập trọng số giữa 2 đỉnh trên đồ thị.
Ví dụ: Đường đi từ đỉnh A đến D có trọng số e1 = 1
Đường đi từ đỉnh F đến G có trọng số e10 = 6

CODE:

> tso:=eweight(dothi):
>tso[e1]:=1:tso[e2]:=2:tso[e3]:=3:tso[e4]:=4:tso[e5]:=5:tso[e6]:=6:tso[e7]
:=1:tso[e8]:=2:tso[e9]:=4:tso[e10]:=6:tso[e11]:=1:tso[e12]:=2:tso[e13]:=4
:tso[e14]:=8:

3.5, Hàm vẽ đồ thị


- 15 -
Giảng viên: Thầy giáo Nguyễn Hữu Điển
Sinh viên thực hiện: Lê Văn Cường & Nguyễn Thị Hòa
Mô phỏng thuật toán Dijkstra

CODE:
>draw(Linear([C,E,H], [D,F,I], [A,G,B],[S]), dothi);

3.6, Đỉnh bắt đầu


Ta truyền tham số dothi và biến S là đỉnh xuất phát vào hàm Dijkstra,
kết quả sẽ được lưu vào mảng ngan1

CODE:

>ngan1:=dijkstra(dothi,S);

3.6, Đỉnh kết thúc


Vòng lặp sẽ được thực hiện cho đến khi đỉnh H được truyền vào, lúc
đó hàm dijsktra sẽ thực hiện và đưa ra đường đi ngắn nhất .

CODE:

- 16 -
Giảng viên: Thầy giáo Nguyễn Hữu Điển
Sinh viên thực hiện: Lê Văn Cường & Nguyễn Thị Hòa
Mô phỏng thuật toán Dijkstra

>ngan1[1][H];

3.7, Lộ trình đường đi ngắn nhất từ đỉnh S đến đỉnh H

CODE:

>listpath(ngan1,S,H);

PHẦN C: KẾT LUẬN

Trên đây là cơ bản về chương trình. Nội dung chính xác mã nguồn
Thầy có thể xem ở tệp Dijkstra_full.mws

TÀI LIỆU THAM KHẢO

* [1] - "Giáo trình Maple", Nguyễn Hữu Điển (chủ biên).


*[2] - Một số tài liệu tham khảo trên Website:
+ www.nhdien.wordpress.com.
+ www.google.com.vn

- 17 -
Giảng viên: Thầy giáo Nguyễn Hữu Điển
Sinh viên thực hiện: Lê Văn Cường & Nguyễn Thị Hòa

You might also like