当图中没有环时,使用Bellman-Ford这一低效算法显然就不划算了,这时我们可以选择DAG算法。
本文使用C++实现了这一基本算法。参考《算法导论》第24.2节
笔者使用了vector实现邻接链表,以提高运行效率。
/**
* DAG's Single Source Shortest Path Algorithm in C++
* Based on DFS, don't let any circle exist in the graph
* Time Cost : O(|N|+|M|)
* Introduction to Algorithms (CLRS) 24.2
* Author: Zheng Chen / Arclabs001
* Copyright 2015 Xi'an University of Posts & Telecommunications
*/
#include <iostream>
#include <vector>
#include <stack>
#include <fstream>
#define INF 0xfffffff
using namespace std;
const int N = 6;
const int M = 10;
ifstream in;
enum status {UNDISCOVERED,DISCOVERED,VISITED};
struct edge
{
int dest;
int weight;
};
struct vertex
{
int num;
int dist;
int inDegree,outDegree;
status _stat;
vertex * parent;
}V[N];
vector<edge> AdjList[N];
stack<int> vertexStack; //The call srack
stack<int> topo_order;
int t;
void initialize(int s)
{
for(int i=0; i<N; i++)
{
V[i].num = i;
V[i].dist = INF;
V[i].parent = nullptr;
V[i].inDegree = 0;
V[i].outDegree = 0;
V[i]._stat = UNDISCOVERED;
AdjList[i].clear();
}
for(int i=0; i<M; i++) //Read informations of edges and insert into the Adjacent List
{
int _start, _dest, _weight;
edge * tmp = new edge;
in>>_start>>_dest>>_weight;
tmp->dest = _dest;
tmp->weight = _weight;
V[_start].outDegree++;
V[_dest].inDegree++;
AdjList[_start].push_back(*tmp);
}
V[s].dist = 0;
t = 0;
}
void relax(int u, int v, int weight) //The "relax" operation
{
if(V[v].dist > V[u].dist + weight)
{
V[v].dist = V[u].dist + weight;
V[v].parent = &V[u];
}
}
/**
* The main dfs-visit function, to get the topo-order of the graph
* @param i [the root of each tree]
*/
void dfs_Visit(int i)
{
V[i]._stat = DISCOVERED;
edge tmp;
for(int j=0; j<V[i].outDegree; j++)
{
tmp = AdjList[i][j];
if(V[tmp.dest]._stat == UNDISCOVERED)
{
dfs_Visit(tmp.dest);
}
}
V[i]._stat = VISITED;
topo_order.push(i);
}
void topo_sort()
{
for(int i=0; i<N; i++)
{
if(V[i]._stat == UNDISCOVERED)
{
dfs_Visit(i);
}
}
}
void DAG_shortest_path(int s)
{
initialize(s);
topo_sort();
while(!topo_order.empty())
{
edge tmp;
int tmp_vertex = topo_order.top();
//cout<<"Now stack top is : "<<topo_order.top()<<endl;
topo_order.pop();
for(int j=0; j<V[tmp_vertex].outDegree; j++)
{
tmp = AdjList[tmp_vertex][j];
relax(tmp_vertex,tmp.dest,tmp.weight);
}
}
}
void print_path(vertex *s, vertex *v)
{
if(v == s)
cout<<s->num;
else if(v->parent == nullptr)
cout<<"No path from "<<s->num<<" to "<<v->num<<endl;
else
{
print_path(s,v->parent);
cout<<"->"<<v->num;
}
}
int main()
{
in.open("DAG.txt");
int s = 1;
DAG_shortest_path(s);
cout<<"Succeed ! The distance of each vertex are :"<<endl;
for(int i=0; i<N; i++) if(V[i].dist == INF) cout<<"INF "; else cout<<V[i].dist<<" ";
cout<<endl<<"One of the shortest path is :"<<endl;
print_path(&V[1],&V[5]);
return 0;
}
/*
Pseudo-Code :
DAG-SHORTEST-PATHS(G,w,s)
topologically sort the vertices of G
Initialize-Single-Source(G,s)
for each vertex u, taken in topologically sorted order
for each vertex v in Adj[u]
Relax(v,u,w)
*/
//DAG.txt文件内容如下:
0 1 5
0 2 3
1 2 2
1 3 6
2 3 7
2 4 4
2 5 2
3 4 -1
3 5 1
4 5 -2
每一行的三个元素分别表示某条边的起始节点、终止节点、这条边的权重。