Dijkstra算法(讀者可以將其讀作“迪傑斯特拉算法”)用來解決單源最短路問題,給定圖G和起點s,通過算法得到S到達其他每個頂點的最短距離。
算法基本思想:
1、對圖G(V,E)設置集合S,存放已被訪問的頂點。
2、每次從集合V-S中選擇與起點s的最短距離最小的一個頂點(記爲u),訪問並加入集合S。
3、令頂點u爲中介點,優化起點s與所有從u能到達的頂點v之間的最短距離。
4、這樣的操作執行n次(n爲頂點個數),直到集合S已包含所有頂點。
題目描述
圖片來自於算法筆記
樣例:
輸入:
6 8 0//6個頂點,8條邊,起點爲0號。以下8行爲8條邊
0 1 1//邊0->1的邊權爲1,下同
0 3 4
0 4 4
1 3 2
2 5 1
3 2 2
3 4 3
4 5 3
輸出:
0 1 5 3 4 6
運行結果:
書中給出兩種解決方法:
1、使用鄰接矩陣來存儲圖的信息
2、使用鄰接表來存儲圖的信息
上邊兩種算法只是在尋找最短路徑的時候不同,其他的都相同
實際上,使用 stl 庫中的priority_queue可以更快的求解,且時間複雜度爲O(V*logV+E)
下面爲代碼:
#include<iostream>
#include<queue>
#include<vector>
#include<map>
#include<algorithm>
#include<limits.h>
#include<stack>
using namespace std;
const int dij_max_v = 101;
struct DijNode
{
int id;//當前結點id
int weight;//到該結點的權值
};
struct MinWeightCompare//小頂堆
{
bool operator() (const DijNode node1, const DijNode node2) const{
return node1.weight > node2.weight;
}
};
//************************************
// Method: dijkstra 返回單源最短路徑
// FullName: dijkstra
// Access: public
// Returns: void
// Qualifier:
// Parameter: vector<DijNode> matrix[] 給定的圖
// Parameter: DijNode start 初始結點
// Parameter: bool * visited 表示當前結點是否被訪問
// Parameter: map<int,int> & parent 表示當前到結點的上一個結點
// Parameter: map<int,int> & distance 表示初始結點到當前結點的最短路徑
//************************************
void dijkstra(vector<DijNode> matrix[], DijNode start, bool* visited, map<int, int>& parent, map<int, int>& distance) {
priority_queue<DijNode, vector<DijNode>, MinWeightCompare> p_queue;//BFS 隊列
//該優先隊列中的元素表示到當前結點的最短路徑。
p_queue.push(start);
while (!p_queue.empty())
{
DijNode top_node = p_queue.top();
p_queue.pop();
visited[top_node.id] = true;//標記當前結點已被訪問
for (int i = 0;i < matrix[top_node.id].size();i++)
{
DijNode next_node = matrix[top_node.id][i];
//當前結點沒有被訪問,且以 top_node 爲中介點可以使得 next_node 更優
if (visited[next_node.id] == false && distance[top_node.id] + next_node.weight < distance[next_node.id])
{
distance[next_node.id] = distance[top_node.id] + next_node.weight;
DijNode node;
node.id = next_node.id;
node.weight = distance[next_node.id];//更新當前的最短距離
p_queue.push(node);//將所遍歷的結點加入到隊列中
parent[next_node.id] = top_node.id;//更新所遍歷結點的父結點
}
}
}
}
//打印start_node 到 end_node 的最短路徑所經過的結點
void print_path(int start_node, int end_node, map<int, int>& parent) {
stack<int> s;
while (start_node != end_node)
{
s.push(end_node);
end_node = parent[end_node];
}
while (!s.empty())
{
int result = s.top();
s.pop();
cout << result << " ";
}
}
int main() {
int n, m, s;//表示頂點個數,邊數,初始結點
cin >> n >> m >> s;
int form_node, to_node, weight;//表示起始結點,終止結點,權值
vector<DijNode> matrix[dij_max_v];//用來存放圖
DijNode node;
map<int, int> parent;//存放當前結點的路徑的上一個結點
parent[s] = -1;//起始結點的父結點爲 -1
map<int, int> distance;//記錄起始結點到其他結點的最短路徑
distance[s] = 0;//自己到自己的距離爲 0
for (int i = 0;i < m;i++)
{
cin >> form_node >> to_node >> weight;
node.id = to_node;
node.weight = weight;
matrix[form_node].push_back(node);
if (to_node != s)
{
distance[to_node] = INT_MAX;//表示除了起始結點,剩下的皆爲不可達
}
}
bool visited[dij_max_v];
fill(visited, visited + dij_max_v, false);
node.id = s;//起始結點的id
node.weight = 0;//起始結點距離自己的距離
dijkstra(matrix, node, visited, parent, distance);
//輸出初始結點到每個結點的最短路徑
for (map<int,int>::iterator it = distance.begin();it != distance.end();it++)
{
cout << (*it).second << " ";
}
system("pause");
return 0;
}