You are on page 1of 23

BỘ CÔNG THƯƠNG

TRƯỜNG ĐẠI HỌC CÔNG THƯƠNG THÀNH PHỐ HỒ CHÍ MINH


KHOA CÔNG NGHỆ THÔNG TIN

TIỂU LUẬN HỌC PHẦN


CẤU TRÚC RỜI RẠC

TÊN ĐỀ TÀI: THUẬT TOÁN DIJKSTRA

NHÓM :10

Thành phố Hồ Chí Minh, tháng 12 năm 2023


BỘ CÔNG THƯƠNG
TRƯỜNG ĐẠI HỌC CÔNG THƯƠNG THÀNH PHỐ HỒ CHÍ MINH
KHOA CÔNG NGHỆ THÔNG TIN

TIỂU LUẬN HỌC PHẦN


CẤU TRÚC RỜI RẠC

TÊN ĐỀ TÀI: THUẬT TOÁN DIJKSTRA


.

NHÓM : 10

GVHD : Đinh Thị Hồng Loan


Lớp : 13DHTH03
SVTH : 2033209004 - Võ Văn Vũ Nhân
2033216510 - Nguyễn Hồng Phi
2033210944 - Đặng Tiểu Bình
2001220524 – Nguyễn Dương Lệ Chi
2001220152 – Nguyễn Phương Anh

TPHCM, Ngày 04 Tháng 12 Năm 2023


Mục lục
LỜI NÓI ĐẦU..........................................................................................................................

Chương 1 - Lý thuyết về thuật toán tìm đường đi ngắn nhất.............................................

1.........Tổng quan..................................................................................................................
1.1......Khái niệm...................................................................................................................
1.2......Ý tưởng cơ bản..........................................................................................................
1.3......Ưu nhược điểm của thuật toán................................................................................
1.4......Ứng dụng....................................................................................................................
2.........Kỹ thuật......................................................................................................................
2.1......Mô tả thuật toán........................................................................................................
2.2......Thời gian chạy...........................................................................................................
2.3......Chứng minh thuật toán...........................................................................................
Chương 2 - Giải thuật_lưu đồ thuật toán dijkstra.............................................................

1.........Phân tích...................................................................................................................
2.........Giải thuật tìm đường đi ngắn nhất giữa một cặp đỉnh........................................
3.........Giải thuật Dijkstra..................................................................................................
Chương 3 – Cài đặt thuật toán.............................................................................................

TÀI LIỆU THAM KHẢO....................................................................................................


LỜI NÓI ĐẦU

Lý thuyết đồ thị là một lĩnh vực nghiên cứu đã có từ lâu đờivà có nhiều ứng
dụng hiện đại.Những tư tưởng cơ bản của lý thuyết đồ thị đươc đề xuất từ những
năm đầu của thế kỷ 18 bởi nhà toán học lỗi lạc người Thụy Sĩ Leonhard
Euler.Chính ông là người đã sử dụng đồ thị để giải bài toán nổi tiếng về các cái
cầu ở thàng phố Konigsberg.
Đồ thị được sử dụng để giải quyết các bài toán trong nhiều lĩnh vực khác
nhau .Chẳng hạn , đồ thị có thể 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ể phân biệt các hợp chất hoá học hữu cơ khác
nhau với cùng công thức phân tử nhưng khác nhau về cấu trúc phân tử nhờ đồ
thị.Chúng ta có thể xác định xem hai máy tính trong mạng có thể trao đổi thông tin
được với nhau hay không nhờ mô hình đồ thị của mạng máy tính. Đồ thị có trọng
số trên các cạnh có thể sử dụng để giải các bài toán như : tìm đường đi ngắn nhất
giữa hai thành phố trong cùng một mạng giao thông . Chúng ta còn sử dụng đồ thị
để giải các bài toán về lập lịch,thời khoá biểu,và phân bố tần số cho các trạm phát
thanh và truyền hình....
Mục đích ta tìm hiểu là nhằm giới thiệu các khái niệm cơ bản,các bài toán
ứng dụng quan trọng của lý thuyết đồ thị như bài toán cây khung nhỏ nhất , bài
toán tìm đường đi ngắn nhất và những thuật toán để giải quyết chúng đã được
trình bày chi tiết cùng với việc phân tích và hướng dẫn cài đặt chương trình
trên máy tính.
Củng cố và rèn luyện kỹ năng lập trình, nhớ lại các thuật toán mà đặc biệt là
thuật toán Dijkstra.
Chương 1 : Lý thuyết về thuật toán tìm đường đi ngắn nhất.
Chương 2 : Giải thuật_lưu đồ thuật toán dijkstra
Chương 3 : Cài đặt thuật toán.
BẢNG PHÂN CHIA CÔNG VIỆC

STT MSSV Tên sinh Công việc được giao Mức độ


viên hoàn thành
(%)
2033216510 Chương 2 : Giải
1 Nguyễn Hồng Phi thuật_lưu đồ thuật toán 100%
dijkstra
203321094 Chương 2 : Giải
2 Võ Văn Vũ Nhân thuật_lưu đồ thuật toán 100%
dijkstra
2033210944 Chương 3 : Cài đặt
3 Đặng Tiểu Bình 100%
thuật toán.
2001220152 Chương 1 : Lý thuyết
4 Nguyễn Phương Anh về thuật toán tìm đường 100%
đi ngắn nhất.
2001220524 Chương 1 : Lý thuyết
5 Nguyễn Dương Lệ Chi về thuật toán tìm đường 100%
đi ngắn nhất.
Chương 1 - Lý thuyết về thuật toán tìm đường đi
ngắn nhất
1. Tổng quan
1.1. Khái niệm
Thuật toán Dijkstra mang tên của nhà khoa học máy tính người Hà Lan
Edsger Dijkstra vào năm 1956 và ấn bản năm 1959, là một thuật toán giải quyết
bài toán đường đi ngắn nhất từ một đỉnh đến các đỉnh còn lại của đồ thị có hướng
không có cạnh mang trọng số không âm.
Thuật toán Dijkstra dựa trên nguyên tắc giảm bớt. Trong đó các giá trị chính
xác hơn sẽ dần thay thế một giá trị gần đúng với khoảng cách chính xác cho đến
khi đạt được khoảng cách ngắn nhất.
Có thể được triển khai bằng nhiều ngôn ngữ lập trình khác nhau, như Python,
C++, Java, v.v.
Có thể được so sánh với các thuật toán khác cùng giải quyết bài toán đường
đi ngắn nhất, như thuật toán Bellman-Ford hoặc thuật toán A.
1.2. Ý tưởng cơ bản
 Thuật toán Dijkstra là bắt đầu từ đỉnh nguồn và lần lượt duyệt qua tất cả các
đỉnh còn lại của đồ thị. Tại mỗi đỉnh, thuật toán sẽ tìm ra cạnh có trọng số
nhỏ nhất nối đỉnh đó với một đỉnh đã được duyệt. Cạnh này sẽ được thêm
vào đường đi ngắn nhất từ đỉnh nguồn đến đỉnh hiện tại. Quá trình này
được lặp lại cho đến khi tất cả các đỉnh đều đã được duyệt.
 Thuật toán Dijkstra có thể được giải thích bằng cách sử dụng một tập hợp
các đỉnh đã được duyệt và một tập hợp các đỉnh chưa được duyệt. Tập hợp
các đỉnh đã được duyệt chứa tất cả các đỉnh đã được duyệt và có đường đi
ngắn nhất từ đỉnh nguồn. Tập hợp các đỉnh chưa được duyệt chứa tất cả các
đỉnh chưa được duyệt.
 Thuật toán Dijkstra hoạt động theo các bước sau:
Bước 1: Từ đỉnh gốc, khởi tạo khoảng cách tới chính nó là 0, khởi tạo
khoảng cách nhỏ nhất ban đầu tới các đỉnh khác là +∞. Ta được danh sách các
khoảng cách tới các đỉnh.
Bước 2: Chọn đỉnh a có khoảng cách nhỏ nhất trong danh sách này và ghi
nhận. Các lần sau sẽ không xét tới đỉnh này nữa.
Bước 3: Lần lượt xét các đỉnh kề b của đỉnh a. Nếu khoảng cách từ đỉnh gốc
tới đỉnh b nhỏ hơn khoảng cách hiện tại đang được ghi nhận thì cập nhật giá trị và
đỉnh kề a vào khoảng cách hiện tại của b.
Bước 4: Sau khi xét tất cả đỉnh kề b của đỉnh a. Lúc này ta được danh sách
khoảng cách tới các điểm đã được cập nhật. Quay lại Bước 2 với danh sách này.
Thuật toán kết thúc khi chọn được khoảng cách nhỏ nhất từ tất cả các điểm.
Thuật toán Dijkstra có độ phức tạp thời gian là O(ElogV), trong đó E là số
cạnh của đồ thị và V là số đỉnh của đồ thị.
1.3. Ưu nhược điểm của thuật toán
 Một số ưu điểm của thuật toán Dijkstra:
Một trong những ưu điểm chính của nó là sự phức tạp nhỏ gần như tuyến
tính.
Nó có thể được sử dụng để tính toán đường dẫn ngắn nhất giữa một nút duy
nhất đến tất cả các nút khác và một nút nguồn duy nhất đến một nút đích duy nhất
bằng cách dừng thuật toán khi đạt được khoảng cách ngắn nhất cho nút đích.
Nó chỉ hoạt động cho các biểu đồ có hướng, có trọng số và tất cả các cạnh
phải có các giá trị không âm.
 Mặc dù có nhiều ứng dụng và ưu điểm khác nhau, thuật toán của
Dijkstra cũng có những nhược điểm, chẳng hạn như;
Nó thực hiện một cuộc thăm dò bị che khuất tiêu tốn rất nhiều thời gian trong
khi xử lý,
Nó không thể xử lý các cạnh âm.
Khi nó hướng đến đồ thị tuần hoàn, do đó không thể đạt được đường đi ngắn
nhất chính xác.
Ngoài ra, cần phải duy trì theo dõi các đỉnh, đã được truy cập.
1.4. Ứng dụng
Tính năng chính của thuật toán Djikstra là tìm ra con đường ngắn nhất mà bộ não
của chúng ta không thể tính toán. Thuật toán này được sử dụng bởi nhiều ứng
dụng thông minh. Ví dụ điển hình là Google Maps của Mỹ và Baidu Maps của
Trung Quốc.
Một số ứng dụng thường gặp của Dijkstra có thể kể đến như:
 Định tuyến mạng
Dijkstra được sử dụng rộng rãi trong việc định tuyến mạng, như định tuyến
trong mạng máy tính, giao thức định tuyến trong Internet (như OSPF và IS-IS),
hay tìm đường đi trong các hệ thống mạng phân tán.
 Ứng dụng trong giao thông, logistic
Trong các hệ thống vận chuyển hoặc giao thông, thuật toán Dijkstra được sử
dụng để tìm đường đi ngắn nhất giữa các địa điểm. Ví dụ, trong ứng dụng dẫn
đường GPS, thuật toán Dijkstra được sử dụng để tính toán đường đi ngắn nhất từ
vị trí hiện tại đến đích.
 Quản lý tài nguyên
Đối với việc quản lý tài nguyên trong hệ thống phân tán, thuật toán Dijkstra
được sử dụng để tìm đường đi ngắn nhất từ nguồn tới các tài nguyên khác nhau. Ví
dụ, trong hệ thống phân tán, có thể sử dụng thuật toán Dijkstra để tìm đường đi
ngắn nhất giữa các nút để truyền tin nhắn hoặc truy cập tài nguyên.
 Phát triển các ứng dụng game
Đối với các trò chơi game, Dijkstra được sử dụng để tìm đường đi ngắn nhất
của nhân vật, xe tăng, hoặc các đối tượng di chuyển khác trong một môi trường đồ
họa 2D hoặc 3D. Điều này giúp xác định các đường đi tối ưu và tạo ra trải nghiệm
chơi game hấp dẫn.
 Mạng xã hội
Đối với ứng dụng mạng xã hội, Dijkstra giúp xác định đường đi ngắn nhất
giữa các nút chức năng, đồng thời hỗ trợ cho việc kết nối giữa các người dùng.
Dựa trên thuật toán này, mạng xã hội có thể đưa ra đề xuất bạn bè có mối quan hệ
gần nhất. Hoặc, nó cũng được sử dụng nhằm xác định các liên kết tối ưu để cải
thiện hiệu suất mạng xã hội, ví dụ như tối ưu hóa quá trình chia sẻ thông tin hoặc
lan truyền tin tức trong mạng.
2. Kỹ thuật
2.1. Mô tả thuật toán
Giả sử bạn muốn tìm con đường ngắn nhất giữa hai điểm xuất phát và điểm
đến trên bản đồ thành phố. Ban đầu, thuật toán của Djikstra đánh dấu khoảng cách
giữa mọi giao lộ khác trên bản đồ bằng vô cực. Nó được thực hiện để thể hiện rằng
những giao lộ đó chưa được truy cập. Một số biến thể của phương pháp này để
giảm khoảng cách giữa các giao lộ. Trong mỗi lần lặp, hãy chọn giao lộ hiện tại.
Trong lần lặp đầu tiên, giao lộ hiện tại sẽ là điểm bắt đầu và khoảng cách đến nhãn
giao lộ sẽ bằng không. Giao lộ hiện tại sẽ là giao lộ chưa được truy cập gần nhất
với điểm xuất phát trong các lần lặp sau lần đầu tiên.
Giao lộ hiện tại được kết nối trực tiếp với mọi giao lộ chưa được truy cập.
Được thực hiện bằng cách xác định tổng khoảng cách giữa giao lộ chưa truy cập
và giá trị của giao lộ hiện tại. Nếu giá trị tổng nhỏ hơn giá trị hiện tại của giao lộ,
thì giao lộ chưa truy cập sẽ được gắn nhãn lại. Thực tế, giao lộ được gắn nhãn lại
nếu đường dẫn đến nó qua giao lộ hiện tại ngắn hơn các đường dẫn trước đây đã
được biết. Để dễ dàng nhận dạng đường đi ngắn nhất, nếu bạn gắn nhãn hoặc dán
nhãn lại, hãy đánh dấu đường bằng mũi tên chỉ đến giao lộ được gắn nhãn lại và
xóa tất cả các đường chỉ khác. Sau khi bạn cập nhật khoảng cách đến từng giao lộ
lân cận, hãy đánh dấu giao lộ hiện tại là đã truy cập và chọn một giao lộ chưa được
truy cập với khoảng cách tối thiểu (từ điểm xuất phát) hoặc nhãn thấp nhất làm
giao lộ hiện tại. Các giao lộ được đánh dấu là đã ghé thăm không được xem lại
hoặc quay trở lại và chỉ có con đường ngắn nhất từ điểm xuất phát.
Để cập nhật các giao lộ lân cận trong thời gian ngắn nhất, đánh dấu giao lộ
hiện tại là đã truy cập và di chuyển đến giao lộ gần nhất chưa được truy cập cho
đến khi bạn đánh dấu điểm đến là đã ghé thăm. Khi bạn đánh dấu một điểm đến là
đã truy cập (như trong bất kỳ giao lộ nào), bạn đã biết con đường ngắn nhất để đến
đó từ điểm xuất phát và bạn có thể theo dõi hành trình của mình theo các mũi tên
ngược lại.
Như dự đoán, thuật toán này không cố gắng "thăm dò" đích trực tiếp. Ngoài
ra, điều duy nhất cần xem xét khi xác định giao lộ "hiện tại" là khoảng cách từ
điểm xuất phát. Do đó, thuật toán này mở rộng ra ngoài từ điểm bắt đầu bằng cách
xem xét tương tác của mọi nút gần hơn về khoảng cách ngắn nhất cho đến khi nó
đến đích. Điều này cho thấy rằng thuật toán cần phải tìm ra con đường ngắn nhất.
Mặt khác, sự chậm chạp tương đối của thuật toán là một điểm yếu của nó trong
một số cấu trúc liên kết.
2.2. Thời gian chạy
Để hiển thị giới hạn thời gian chạy của thuật toán Djikstra trên đồ thị có cạnh
E và đỉnh V có thể được biểu hiện dưới dạng hàm số cạnh được gọi là |E|, và số
đỉnh |V| sử dụng ký hiệu big-O. Độ phức tạp của tập hợp Q chủ yếu phụ thuộc vào
cấu trúc dữ liệu được sử dụng để hiển thị nó. Giới hạn trên có thể được đơn giản
hóa sau đây vì |E| là O(|V| 2). Đối với bất kỳ đồ thị nào, những sự đơn giản hóa đó
bỏ qua thực tế là các giới hạn trên khác trên |E| có thể được duy trì trong một số
trường hợp. Thời gian chạy đối với bất kỳ cấu trúc dữ liệu cho tập đỉnh Q nào là

trong Tdk và Tem lần lượt là sự phức tạp của các phép
toán giảm và trích xuất tối thiểu trong Q.
Phiên bản đơn giản nhất của thuật toán Djikstra lưu trữ tập đỉnh Q trong
mảng được liên kết hoặc danh sách và các cạnh trong danh sách hoặc ma trận liền
kề. Trong trường hợp này, extract-minimum chỉ là một tìm kiếm tuyến tính qua tất

cả các đỉnh của Q, vì vậy thời gian chạy là


Đối với đồ thị thưa thớt, nghĩa là đồ thị có ít hơn nhiều |V| 2 Lưu trữ biểu đồ
dưới dạng danh sách liền kề và sử dụng cây tìm kiếm nhị phân tự cân bằng, đống
nhị phân, đống ghép nối hoặc đống Fibonacci làm hàng đợi ưu tiên để thực hiện
trích xuất tối thiểu một cách hiệu quả là một cách để thực hiện thuật toán Djikstra
Để thực hiện các bước giảm phím trong một đống nhị phân một cách hiệu quả, cần
có một cấu trúc dữ liệu phụ trợ ánh xạ từng đỉnh đến vị trí của chúng trong đống
và giữ cho cấu trúc này được cập nhật khi hàng đợi ưu tiên Q thay đổi. Với đống
nhị phân hoặc cây tìm kiếm nhị phân tự cân bằng, thuật toán yêu cầu

thời gian trong trường hợp xấu nhất (trong đó log biểu thị
logarit nhị phân log2). Đối với các đồ thị kết nối, giới hạn thời gian này có thể

được đơn giản thành đống Fibonacci cải thiện điều này thành

Khi sử dụng đống nhị phân, độ phức tạp thời gian trường hợp trung bình thấp
hơn trường hợp xấu nhất. Ví dụ, giả sử chi phí cạnh được tính riêng cho phân phối
xác suất chung, số lượng phép toán giảm khóa dự kiến bị giới hạn bởi

cho tổng thời gian chạy là


2.3. Chứng minh thuật toán
Bằng chứng về thuật toán của Dijkstra được xây dựng bằng cách cảm ứng
trên số lượng nút được truy cập.
Giả thuyết bất biến nói rằng khoảng cách từ nguồn đến v (mỗi nút được truy
cập v) và khoảng cách từ nguồn đến u (mỗi nút u chưa được truy cập) là khoảng
cách ngắn nhất từ nguồn đến u khi chỉ di chuyển qua các nút đã truy cập hoặc vô
cực nếu không có đường dẫn.
Trường hợp cơ sở là khi chỉ có một nút được truy cập, cụ thể là nguồn nút
ban đầu, trong trường hợp đó giả thuyết là tầm thường.
Giả thuyết cho các nút truy cập k-1 được giả sử tiếp theo. Chúng tôi sử dụng
thuật toán để chọn u là nút truy cập tiếp theo. Chúng tôi tuyên bố rằng khoảng
cách ngắn nhất giữa nguồn và u là dist [u]. Đường dẫn ngắn hơn có thể chứa một
nút khác chưa được truy cập hoặc không.
Trong trường hợp đầu tiên, hãy đặt nút không được truy cập đầu tiên trên
đường dẫn ngắn nhất là w. Theo giả thuyết quy nạp, đường dẫn ngắn nhất từ
nguồn đến u và w thông qua nút truy cập chỉ có chi phí dist [u] và dist [w]. Chi phí
đi từ nguồn đến u qua w phải bằng tối thiểu dist [w] + chi phí đi từ w đến u. Chi
phí tối thiểu để di chuyển từ w đến u là một con số dương vì chi phí cạnh là
dương. Thuật toán đã chọn u thay vì w, dist [u] < dist [w].
Mâu thuẫn rằng dist [u] < dist [w] nhưng dist [w] + một số dương < dist
[u].
Trong trường hợp thứ hai, hãy đảm bảo rằng w là nút cuối cùng nhưng vẫn là
nút duy nhất trên đường dẫn ngắn nhất. Nói cách khác, dist [w] + Graph.Edges [w,
u] tương đương với dist [u]. Đó là mâu thuẫn vì dist [u] phải được đặt thành nhiều
nhất là dist [w] + Graph.Edges [w, u] khi w được truy cập.
Giả thuyết quy nạp cho chúng ta biết dist [v] là khoảng cách ngắn nhất từ
nguồn và bước thuật toán không thay đổi đối với tất cả các nút v đã truy cập.
Sau khi xử lý u, vẫn đúng là dist [w] sẽ là khoảng cách ngắn nhất từ nguồn
đến w chỉ sử dụng các nút đã truy cập đối với mỗi nút w chưa được truy cập. Điều
này là do chúng tôi sẽ xác định trước nếu có một đường dẫn ngắn hơn không đi
theo u và nếu có một đường d
Đường dẫn ngắn nhất từ nguồn đến bất kỳ nút v nào chỉ bao gồm các nút đã
truy cập sau khi tất cả các nút đã được truy cập, do đó dist [v] là khoảng cách ngắn
nhất.
Chương 2 - Giải thuật_lưu đồ thuật toán dijkstra
1. Phân tích
Dùng ma trận kề để biểu diễn đồ thị C= (cij), cij = trọng số của cung (i,j), cij
=+∞ nếu không có cung (i,j). Một mảng d[] để ghi các độ dài đường đi ngắn nhất
từ s tới đỉnh i đang có . Xuất phát d[s] =0 và d[i] =c si nếu i kề s, d[j] =+ ∞ nếu j
không kề s.
2. Giải thuật tìm đường đi ngắn nhất giữa một cặp đỉnh
Định nghĩa 1.0. Xét đồ thị có trọng số cạnh G = (V,E,w), với hàm trọng số
w:E⟶ R là ánh xạ từ tập các cạnh E đến tập số thực R.
Định nghĩa 1.1. Đường đi p từ đỉnh u đến đỉnh v là dãy các cạnh nối tiếp
nhau bắt đầu từ đỉnh u kết thúc tại đỉnh v. Đường đi p từ u đến v được biểu diễn
như sau: p=(u=v0,v1…,vk=v)
Định nghĩa 1.2. Độ dài của đường đi p = ( v0,v1,...,vk ), ký hiệu ���(p), là
tổng các trọng số của các cạnh trên đường đi:

Định nghĩa 1.3. Gọi à (u,v) là tập tất cả đường đi từ u đến v. Độ dài
đường đi ngắn nhất từ đỉnh u đến đỉnh v được xác định bởi:

Định nghĩa 1.4. Đường đi ngắn nhất pmin(u,v) từ đỉnh u đến đỉnh v là

đường đi có độ dài d(u,v).

3. Giải thuật Dijkstra

a. Nội dung
Có rất nhiều giải thuật đã được phát triển để giải bài toán tìm đường đi ngắn
nhất giữa một cặp đỉnh, trong khuôn khổ bài viết này em chỉ xin giới thiệu giải
thuật Dijkstra. Giải thuật Dijkstra là một giải thuật để giải bài toán đường đi ngắn
nhất nguồn đơn trên một đồ thị có trọng số cạnh mà tất cả các trọng số đều không
âm. Nó xác định đường đi ngắn nhất giữa hai đỉnh cho trước, từ đỉnh a đến đỉnh b.

Ở mỗi đỉnh v, giải thuật Dijkstra xác định 3 thông tin: k v, dv và pv. kv:
mang giá trị boolean xác định trạng thái được chọn của đỉnh v.

Ban đầu ta khởi tạo tất cả các đỉnh v chưa được chọn, nghĩa là:

kv = false,  v ∈ V.

dv: là chiều dài đường đi mà ta tìm thấy cho đến thời điểm đang xét từ a
đến v.

Khởi tạo, dv = ¥, "v ∈ V \{a}, da = 0.


pv: là đỉnh trước của đỉnh v trên đường đi ngắn nhất từ a đến b. Đường đi
ngắn nhất từ a đến b có dạng {a,...,pv,v,...,b}. Khởi tạo, pv = null, "v∈ V.
Sau đây là các bước của giải thuật Dijkstra:

B1. Khởi tạo: Đặt kv:= false "v ∈ V; dv:= ¥,"v ∈ V \ {a}, da:=0. B2.Chọn
v ∈ V sao cho kv = false và dv = min {dt / t∈ V, kt = false} Nếu dv = ¥ thì kết thúc,
không tồn tại đường đi từ a đến b.
B3. Đánh dấu đỉnh v, kv:= true.
B4. Nếu v = b thì kết thúc và db là độ dài đường đi ngắn nhất từ a đến b.
Ngược lại nếu v ¹ b sang B5.
B5. Với mỗi đỉnh u kề với v mà ku = false, kiểm tra Nếu du > dv + w(v,u)
thì du:= dv + w(v,u)
Ghi nhớ đỉnh v: pu:= v.Quay lại B2.

b. Độ phức tạp của giải thuật Dijkstra

*** Trường hợp sử dụng ma trận kề.


Gọi f(n) là số lần giải thuật Dijkstra khảo sát một cạnh của đồ thị G trong
trường hợp xấu nhất. Khi đó ta có:

f(n) < O(|V|2)


Chứng minh: Cho n = |V|, B5 là vòng lặp chứa các bước B2 ⟶ B5, vòng
lặp được thực hiện đến khi v = b.Vì ở mỗi vòng lặp ta rút ra một đỉnh của V và
khởi đầu V có n phần tử, nên vòng lặp được xử lý nhiều nhất là n lần.

Ở B2 số đỉnh tối đa được khảo sát là n - 1 đỉnh Ở B5 số đỉnh kề tối đa được


khảo sát là n -1 đỉnh

Do đó: f(n) £ 2(n-1)n < O(|V|2) Vậy độ phức tạp của giải thuật
Dijkstra là O(|V|2).
*** Trường hợp sử dụng danh sách kề
Độ phức tạp của giải thuật Dijkstra là O((|V| + |E|)lg|V|).
c. Lưu đồ thuật toán Dijkstra
d. Tạo bảng dữ liệu chạy tay

Tạo ma trận như sau


Ta có đồ thị như sau
6
042000
401500
2 1 0 8 10 0
058026
0 0 10 2 0 3
000630
Ta có đồ thị như sau:

Bảng chạy thô

V T a b e c f d độ
0 ¥ ¥ ¥ ¥ ¥
dài
a bcdef * 4 2* ¥ ¥ ¥
e bcfd 3* * 10 12 ¥ từ
b cfd * 8* 12 ¥ a-
c fd * 12* 14
>f
f d * 15
d * là
15
Chương 3 – Cài đặt thuật toán
Đề tài : Chương trình tìm đường đi ngắn nhất từ đỉnh S đến đỉnh T theo
thuật toán Dijkstra _Sử dụng ngôn ngữ lập trình C
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include <math.h>

#define Max 50

int final[Max];
int V; // So Dinh
int start, end; // Diem Xuat Phat va Ket Thuc

void Init (int CP[Max][Max]){


int i, j;
FILE *f = fopen ("MaTranTrongSo.txt", "r");
fscanf(f, "%d", &V);
printf("\n Bai Toan Tim Duong Di Ngan Nhat Tren Do Thi -
ShortestPath");
printf("\n Do Thi Co %d Dinh", V);
printf("\n Ma Tran Chi Phi Tren Do Thi la: ");
for (i = 1; i <= V; i++){
printf("\n");
for (j = 1; j <= V; j++){
fscanf(f, "%d", &CP[i][j]);
printf(" %2d", CP[i][j]);
if (CP [i][j] == 0)
CP[i][j] = 32000;
}
}
fclose(f);
}

void Display (int truoc[Max], int d[Max]){


int i, j;
printf("\n Duong Di Ngan Nhat tu %d den %d la: ", start, end);
printf(" %d <-- ", end);
i = truoc[end];

while (i != start){
printf("%d <-- ", i);
i = truoc[i];
}

printf("%d", start);
printf("\n Do Dai Duong Di la: %d", d[end]);
getch();
}

void Dijkstra (int CP[Max][Max], int truoc[Max], int d[Max]){


int u, v, minp;
printf("\n Nhap vao Vi Tri Xuat Phat: "); scanf("%d", &start);
printf("\n Nhap vao Vi Tri Dich: "); scanf("%d", &end);

for (v = 1; v <= V; v++){


d[v] = CP[start][v];
truoc[v] = start;
final[v] = 0;
}

truoc[start] = 0;
d[start] = 0;
final[start] = 1;

while (!final[end]){
minp = 2000;
for (v = 1; v <= V; v++){
if (!final[v] && (minp > d[v])){
u = v;
minp = d[v];
}
}

final[u] = 1; // u la Dinh co Nhan Temp Nho Nhat


if (!final[end]){
for (v = 1; v <= V; v++){
if (!final[v] && (d[u] + CP[u][v] < d[v])){
d[v] = d[u] + CP[u][v];
truoc[v] = u;
}
}
}
}
}
int main (){
int CP[Max][Max]; // Ma Tran Chi Phi
int truoc[Max] = {};
int d[Max] = {}; // Do Dai Duong Di

Init (CP);
Dijkstra(CP, truoc, d);
Display (truoc, d);
return 0;
}
TÀI LIỆU THAM KHẢO

You might also like