一.Dijikstra算法
注意:计算最短路径时,需要把邻接矩阵中没有边的位置初始化为无穷大;此处以INF表示,INF可以取0x3f3f3f3f,不能直接设为INT_MAX(因为做加法时会上溢)。
测试用图:
其邻接矩阵表示为:
vector<vector<int>> test_graph(7, vector<int>(7, INF));
test_graph[0][1] = 20;
test_graph[0][2] = 50;
test_graph[0][3] = 30;
test_graph[1][2] = 25;
test_graph[1][5] = 70;
test_graph[2][3] = 40;
test_graph[2][4] = 25;
test_graph[2][5] = 50;
test_graph[3][4] = 55;
test_graph[4][5] = 10;
test_graph[4][6] = 70;
test_graph[5][6] = 50;
其中INF为:
const int INF = 0x3f3f3f;//不能取得太大(dijikstra中会用到,其余情况没边用0表示即可)
代码:
//pre记录前缀
const int INF = 0x3f3f3f;//不能取得太大(dijikstra中会用到,其余情况没边用0表示即可)
void dijkstra(graph g, vector<int>& lowcost, vector<int>& pre, int beg) {//第二、三个参数为传出参数,分别表示从源节点beg,到所有节点的最短路路径
size_t N = g.cost.size();
vector<bool> visited(N, false);
for (size_t i = 0;i < N;++i) {//初始化lowcost和pre
lowcost[i] = INF;
pre[i] = -1;
}
lowcost[beg] = 0;//出发点到自己的最短路径是0
for (size_t i = 0;i < N;++i) {
int newNode = -1;//下一个要被选中的点的编号, 初始化为 - 1
int MinWeight=INF;//与当前节点相邻的边的最小权值
//第一个for,遍历所有的未被访问过的节点,选中间点(已选节点之外的离出发点距离最短的点)
for (size_t j = 0;j < N;++j) {
if (!visited[j] && lowcost[j] < MinWeight) {
MinWeight = lowcost[j];
newNode = j;
}
}
if(-1==newNode)
break;//图不连通时,退出
visited[newNode] = true;//将中间点标记为已访问状态
for (size_t j = 0;j < N;++j) {
if (!visited[j] && lowcost[newNode] + g.cost[newNode][j] < lowcost[j]){
lowcost[j] = lowcost[newNode] + g.cost[newNode][j];
pre[j] = newNode;
}
}
}
}
步骤:
1.初始化时,将出发点到自己的最短路径置为0,其余置为无穷
2.对于出发点以外的点(即上面第二个for中所选的点j),考察从出发点直接到它的距离d1=lowcost[j]和先经过一个第一个for所选的中间点(newNode)才到j的距离d2=lowcost[newNode] + g.cost[newNode][j];
3.如果经由中间点然后访问点j的距离比直接访问j的距离短,即步骤2中的d2<d1时,更新出发点到j的最短距离为d2,它的上一个节点即那个中间点newNode
测试部分:
graph g;
g.cost = test_graph;
g.vertex = { "v1","v2","v3","v4","v5","v6","v7" };
vector<int> lowcost(7, 0);
vector<int> pre(7, 0);
dijkstra(g, lowcost, pre, 0);
cout << "从v1其它节点的最短距离分别是: " << endl;
for (size_t i = 0;i < g.vertex.size();++i) {
cout << g.vertex[i] << ";" << lowcost[i] <<" " ;
}
cout << endl;
cout << endl;
cout << "每个节点的前驱是: " << endl;
for (size_t i = 0;i < g.vertex.size();++i) {
cout << g.vertex[i] << "的前驱是: " << ((pre[i] == -1) ? "null" :g.vertex[pre[i]]) << endl;;
}
测试结果: