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;
}