Các thuật toán tìm đường đi ngắn nhất

Dẫn nhập
Trong bài học trước, họ đã thuộc nhau đi kiếm hiểu về thuật toán Floyd-Warshall trong tìm kiếm kiếm đường đi ngắn nhất trên đồ dùng thị. Hôm nay, bọn họ sẽ thuộc nhau đi tìm kiếm hiểu về một thuật toán rất có thể coi là thuật toán thông dụng nhất trong search kiếm đường đi ngắn nhất. Để biết cố gắng thể, hãy thuộc nhau bước đầu bài học tập nào!
Nội dung
Để hoàn toàn có thể tiếp thu bài học kinh nghiệm này một cách giỏi nhất, chúng ta nên gồm những kiến thức cơ bạn dạng về:
Trong bài học kinh nghiệm ngày hôm nay, bọn họ sẽ thuộc nhau tìm hiểu về:
Thuật toán DijkstraThuật toán Dijkstra
Bài toán đặt ra
Ta tất cả một việc như sau:
Cho một đồ thị có hướng gồm





Bạn đang xem: Các thuật toán tìm đường đi ngắn nhất
Input:
Dòng








Output:
Gồm



Ví dụ:
Input | Output |
7 8 1 1 2 4 1 3 5 1 4 2 4 2 1 4 6 4 3 5 3 6 5 1 1 5 8 | 0 3 5 2 7 6 -1 |
Giải đam mê ví dụ:
Đây là đồ dùng thị minh hoạ mang đến ví dụ trên

Ý tưởng
Ý tưởng của Dijkstra về cơ phiên bản khá kiểu như với thuật toán Floyd. Với cùng 1 cạnh nối liền hai đỉnh




Tại từng bước, ta sẽ lựa chọn ra một đỉnh






Cách cài đặt
Trước hết, để diễn tả một cạnh, ta vẫn sử dụng những vector với hình trạng dữ liệupair. Pair là một cấu tạo cho phép ta lưu trữ hai phần tử. Ta rất có thể truy cập vào 2 thành phần củapair thông qua hai phương thứcfirst cùng second.
Ví dụ:
#includeusing namespace std;int main(){ pair myPair<2>; // có 2 phương pháp khởi tạo nên pair myPair<0> = make_pair(1, 2); myPair<1> = 2, 3; cout Ta sẽ nên khởi tạo ra hai mảng với ý nghĩa như sau:
dist: độ dài đường đi ngắn độc nhất từ đỉnh nguồns đến đỉnh u. Lúc đầu dist = ∞ với mọiu, riêng biệt distLưu ý: Trong laptop không tồn tại định nghĩa ∞ (vô cùng). Bởi đó, mỗi lúc viết ∞, ta sẽ hiểu đây là một quý giá đủ to để to hơn giá trị béo nhất rất có thể của mảng đó.

Thuật toán sẽ diễn ra như sau:
Chọn một đỉnh u thế nào cho mark = false cùng dist bé dại nhấtVới đỉnh u nhưng mà ta đã chọn ở trên, ta sẽ xét các đỉnhv gồm cạnh nối trực tiếp từ u. Nếudist + (độ lâu năm cạnh u-v) lúc xét ngừng tất cả các đỉnh bao gồm cạnh nối trực tiếp từu, khắc ghi mark = true tức là đỉnhu đã xử trí xong.Minh hoạ
Mình vẫn minh họa thuật toán bằng một trang bị thị cơ bạn dạng sau với đỉnh nguồn là đỉnh 1:

Code cơ bản
Code#includeusing namespace std;typedef long long ll;const int MaxN = 1 + 1e2;const ll INF = 1e18;int n, m, s;bool mark = 0; for(int i = 1 ; i > n >> m >> s; for(int i = 0 ; i > u >> v >> w; adj.push_back(v, w); Dijkstra(s); for(int i = 1 ; i Độ phức tạpTa thấy trong khúc code trên, ta có một vòng lặp bên cạnh cùng tất cả độ phức tạp
Do đó, độ phức tạp tổng thể của công tác là

Xem thêm: Hướng Dẫn Sử Dụng Hàm Sumif Trong Excel: Cách Sử Dụng Và Ví Dụ Cụ Thể
Code cải tiến
Ý tưởngTa thấy với độ phức hợp trên thì bài toán vẫn không được giải quyết và xử lý trọn vẹn và giải mã sẽ cần được tối ưu thêm. Hiện thời hãy thuộc xem xét các yếu tố hoàn toàn có thể tối ưu được của bài toán.
Vòng lặp dùng để làm duyệt cùng xét tất cả các cạnh sẽ luôn phải xảy ra. Vì chưng đó, vòng lặp này sẽ không thể về tối ưu thêm nữa.
Ta vẫn xét đến vòng lặp dùng để tìm ra đỉnh u códist nhỏ tuổi nhất. Ta thấy ngay việc dùng vòng lặp để tìm ra phần tử nhỏ nhất trong một tập hợp là một điều khá “ngu ngốc”. Ở những bài học kinh nghiệm trước, bản thân đã trình làng cho chúng ta về một cấu trúc dữ liệu rất có thể tìm ra phần tử nhỏ tuổi nhất nhanh chóng. Chúng ta có còn nhớ nó không? Nó đó là priority_queueđó.
Ta sẽ sử dụng priority_queuelưu trữ những pair, trong số đó giá trịfirst là độ dài lối đi ngắn duy nhất từ đỉnh s mang đến đỉnhu, quý hiếm second là đỉnh u. Khipriority_queue đối chiếu cácpair nói thông thường thì nó sẽ đối chiếu giá trịfirst trước rồi new đến giá trị second. Vì thế ta nhằm độ dài lối đi ở giá trịfirst vì lúc đó đỉnh gồm dist<> nhỏ dại nhất đã được mang ra trước.
Code#includeusing namespace std;typedef long long ll;const int MaxN = 1 + 1e2;const ll INF = 1e18;int n, m, s;bool mark = 0; priority_queue, vector>, greater>> pq; pq.push(0, s); while(!pq.empty()) int u = pq.top().second; pq.pop(); if(mark) continue; mark = true; for(auto e : adj) int v = e.first; ll w = e.second; if(dist
Vấn đề kì sau
Để tất cả thể chuẩn bị tốt hơn cho bài học kinh nghiệm kế tiếp, mình muốn đặt ra cho các bạn một câu hỏi:
Ở đề bài mình nêu sinh sống trên, các cạnh đều phải sở hữu trọng số không âm. Điều gì rất có thể sẽ xảy ra với thuật toán Dijkstra nếu các cạnh bao gồm trọng số âm?
Kết luận
Qua bài bác này chúng ta đã thế về Tìm kiếm đường đi ngắn độc nhất trên đồ thịvới thuật toán Dijkstra.
Bài sau chúng ta sẽ tò mò về Tìm kiếm đường đi ngắn nhất trên vật thịvới thuật toán Bellman-Ford.
Cảm ơn các bạn đã theo dõi bài viết. Hãy để lại comment hoặc góp ý của bản thân để phát triển nội dung bài viết tốt hơn. Đừng quên “Luyện tập – thách thức – không lo khó”.
Thảo luận
Nếu bạn có bất kỳ khó khăn hay vướng mắc gì về khóa học, đừng ngần ngại đặt thắc mắc trong phần BÌNH LUẬN bên dưới hoặc vào mục HỎI và ĐÁP trên tủ sách kemhamysophie.com.com để nhận ra sự cung cấp từ cộng đồng.