算法开始对DAG图进行拓扑排序,以便获得结点的线性序列;当对线性序列进行处理时,松弛从该点出发的所有边。
对一个有向无环图(Directed Acyclic Graph简称DAG)G进行拓扑排序,是将G中所有顶点排成一个线性序列,
使得图中任意一对顶点u和v,若<u,v> ∈E(G),则u在线性序列中出现在v之前。
若将图中顶点按拓扑次序排成一行,则图中所有的有向边均是从左指向右的
利用DFS现实拓扑排序,为什么push结点入stack的时机是dfs()即将退出之时,由于dfs()本身是个递归算法,
只要当前结点还存在指向其他结点的边,它将会一直递归调用dfs(),只有当前结点没有指向其他结点的边,
即当前结点是一条路径上的最后一个结点时,它才结束递归。
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <string>
#include <queue>
#include <stack>
#include <list>
using namespace std;
const double MAX = 10000.0;
class DirectedEdge
{
public:
DirectedEdge(int u, int v, double w)
{
if (u >= 0 && v >= 0)
{
this->u = u;
this->v = v;
weight = w;
}
}
int from()
{
return u;
}
int to()
{
return v;
}
double getWeight()
{
return weight;
}
string toString()
{
char result[64] = "";
sprintf(result, "%d -- %d: %8.2f\n", u, v, weight);
string str = result;
return str;
}
private:
int u;
int v;
double weight;
};
class EdgeWeightedDigraph
{
public:
EdgeWeightedDigraph(int nVertex, int nEdge, int arr[][2], double weight[]);
~EdgeWeightedDigraph();
list<DirectedEdge *> getAdj(int v);
list<DirectedEdge *> edges();
int getV() { return V; }
private:
int V;
int E;
list<DirectedEdge *> *adj;
};
EdgeWeightedDigraph::EdgeWeightedDigraph(int nVertex, int nEdge, int arr[][2], double weight[])
{
V = nVertex;
E = nEdge;
adj = new list<DirectedEdge *>[nVertex];
for (int i = 0; i < nEdge; ++i)
{
DirectedEdge *e = new DirectedEdge(arr[i][0], arr[i][1], weight[i]);
adj[arr[i][0]].push_back(e);
}
}
EdgeWeightedDigraph::~EdgeWeightedDigraph()
{
list<DirectedEdge *> ls = edges();
for (list<DirectedEdge *>::iterator it = ls.begin(); it != ls.end(); ++it)
{
delete *it;
*it = NULL;
}
delete []adj;
adj = NULL;
}
list<DirectedEdge *> EdgeWeightedDigraph::getAdj(int v)
{
if (v >= 0 && v < V)
return adj[v];
}
list<DirectedEdge *> EdgeWeightedDigraph::edges()
{
list<DirectedEdge *> ls;
for (int i = 0; i < V; ++i)
{
list<DirectedEdge *> tmpList = getAdj(i);
for (list<DirectedEdge *>::iterator it = tmpList.begin(); it != tmpList.end(); ++it)
ls.push_back(*it);
}
return ls;
}
/**
* Determine whether the edge-weighted digraph G has a directed cycle and if so, find such a cycle
*/
class EdgeWeightedDirectedCycle
{
public:
EdgeWeightedDirectedCycle(EdgeWeightedDigraph *g);
~EdgeWeightedDirectedCycle();
bool hasCycle() { return (cycle.empty() ? false : true) ; }
stack<DirectedEdge *> getCycle() { return cycle; }
private:
void dfs(EdgeWeightedDigraph *g, int s);
private:
bool *marked; // marked[v] = has vertex v been marked
DirectedEdge **edgeTo; // edgeTo[v] = previous edge on path to v
bool *onStack; // onStack[v] = is vertex on the stack
stack<DirectedEdge *> cycle; // directed cycle (null if no such cycle)
};
EdgeWeightedDirectedCycle::EdgeWeightedDirectedCycle(EdgeWeightedDigraph *g)
{
int v = g->getV();
marked = new bool[v];
edgeTo = new DirectedEdge *[v];
onStack = new bool[v];
memset(marked, false, v * sizeof(bool));
memset(onStack, false, v * sizeof(bool));
for (int k = 0; k < v; ++k)
edgeTo[k] = NULL;
for (int i = 0; i < v; ++i)
if (!marked[i])
dfs(g, i);
}
EdgeWeightedDirectedCycle::~EdgeWeightedDirectedCycle()
{
if (NULL != marked)
{
delete []marked;
marked = NULL;
}
if (NULL != edgeTo)
{
delete []edgeTo;
edgeTo = NULL;
}
if (NULL != onStack)
{
delete []onStack;
onStack = NULL;
}
}
void EdgeWeightedDirectedCycle::dfs(EdgeWeightedDigraph *g, int s)
{
onStack[s] = true;
marked[s] = true;
list<DirectedEdge *> ls = g->getAdj(s);
for (list<DirectedEdge *>::iterator it = ls.begin(); it != ls.end(); ++it)
{
int u = (*it)->to();
// short circuit if directed cycle found
if (!cycle.empty())
return ;
else if (!marked[u])
{
edgeTo[u] = *it;
dfs(g, u);
}
else if (onStack[u]) // trace back directed cycle
{
DirectedEdge *e = *it;
while (u != e->from())
{
cycle.push(e);
e = edgeTo[e->from()];
}
cycle.push(e);
}
}
onStack[s] = false;
}
/**
* The DepthFirstOrder class represents a data type for detemining depth first search
* ordering of the vertices in a edge-weighted digraph, including preorder, postorder,
* and reverse post order
*/
class DepthFirstOrder
{
public:
DepthFirstOrder(EdgeWeightedDigraph *g);
~DepthFirstOrder();
int getPre(int v) { return pre[v]; }
int getPost(int v) { return post[v]; }
queue<int> getPostOrder() { return postorder; }
queue<int> getPreOrder() { return preorder; }
stack<int> getReversePostOrder();
private:
void dfs(EdgeWeightedDigraph *g, int s);
private:
bool *marked; // marked[v] = has v been marked in dfs
int *pre; // pre[v] = preorder number of v
int *post; // post[v] = postorder number of v
queue<int> preorder; // vertices in preorder
queue<int> postorder; // vertices in postorder
int preCounter; // counter for preorder numbering
int postCounter; // counter for postorder numbering
};
DepthFirstOrder::DepthFirstOrder(EdgeWeightedDigraph *g)
{
preCounter = 0;
postCounter = 0;
int v = g->getV();
marked = new bool[v];
pre = new int[v];
post = new int[v];
memset(marked, false, v * sizeof(bool));
for (int i = 0; i < v; ++i)
if (!marked[i])
dfs(g, i);
}
DepthFirstOrder::~DepthFirstOrder()
{
if (NULL != marked)
{
delete []marked;
marked = NULL;
}
if (NULL != pre)
{
delete []pre;
pre = NULL;
}
if (NULL != post)
{
delete []post;
post = NULL;
}
}
void DepthFirstOrder::dfs(EdgeWeightedDigraph *g, int s)
{
marked[s] = true;
pre[s] = preCounter++;
preorder.push(s);
list<DirectedEdge *> ls = g->getAdj(s);
for (list<DirectedEdge *>::iterator it = ls.begin(); it != ls.end(); ++it)
{
int u = (*it)->to();
if (!marked[u])
dfs(g, u);
}
postorder.push(s);
post[s] = postCounter++;
}
stack<int> DepthFirstOrder::getReversePostOrder()
{
stack<int> reverseorder;
queue<int> tmp = postorder;
while (!tmp.empty())
{
reverseorder.push(tmp.front());
tmp.pop();
}
return reverseorder;
}
/**
* The topological class represents a data type for determining a topological order of a directed acyclic graph
* (DAG). Recall, a digraph has a topological order if and only if is a DAG
*/
class Topological
{
public:
Topological(EdgeWeightedDigraph *g);
stack<int> getOrder() { return order; }
bool hasOrder() { return (order.empty() ? false : true); }
private:
stack<int> order; // topological order
};
Topological::Topological(EdgeWeightedDigraph *g)
{
EdgeWeightedDirectedCycle find(g);
if (!find.hasCycle())
{
DepthFirstOrder dfs(g);
order = dfs.getReversePostOrder();
}
}
class AcyclicSP
{
public:
AcyclicSP(EdgeWeightedDigraph *g, int s);
~AcyclicSP();
double getDistTo(int v) { return distTo[v]; }
bool hasPathTo(int v) { return distTo[v] < MAX; }
stack<DirectedEdge *> pathTo(int v);
private:
void relax(DirectedEdge *e);
private:
double *distTo; // distTo[v] = distance of shortest s->v path
DirectedEdge **edgeTo; // edgeTo[v] = last edge on shortest s->v path
};
AcyclicSP::AcyclicSP(EdgeWeightedDigraph *g, int s)
{
int v = g->getV();
distTo = new double[v];
edgeTo = new DirectedEdge *[v];
for (int i = 0; i < v; ++i)
{
distTo[i] = MAX;
edgeTo[i] = NULL;
}
distTo[s] = 0.0;
Topological topological(g);
if (topological.hasOrder())
{
stack<int> order = topological.getOrder();
while (!order.empty())
{
int t = order.top();
order.pop();
list<DirectedEdge *> ls = g->getAdj(t);
for (list<DirectedEdge *>::iterator it = ls.begin(); it != ls.end(); ++it)
relax(*it);
}
}
}
AcyclicSP::~AcyclicSP()
{
if (NULL != distTo)
{
delete []distTo;
distTo = NULL;
}
if (NULL != edgeTo)
{
delete []edgeTo;
edgeTo = NULL;
}
}
/**
* Single-source longest paths problem in edge-weighted DAGs.
* We can solve the single-source longest paths problems in edge-weighted DAGs by initializing the distTo[] values to negative infinity
* and switching the sense of the inequality in relax()
*/
void AcyclicSP::relax(DirectedEdge *e)
{
int u = e->from();
int v = e->to();
double w = e->getWeight();
if (distTo[v] > distTo[u]+w)
{
distTo[v] = distTo[u] + w;
edgeTo[v] = e;
}
}
stack<DirectedEdge *> AcyclicSP::pathTo(int v)
{
stack<DirectedEdge *> path;
if (hasPathTo(v))
{
for (DirectedEdge *e = edgeTo[v]; e != NULL; e = edgeTo[e->from()])
{
path.push(e);
}
}
return path;
}
int main()
{
/*
test1:
int arr[][2] = {{2, 3}, {0, 6}, {0, 1}, {2, 0}, {11, 12},
{9, 12}, {9, 10}, {9, 11}, {3, 5}, {8, 7},
{5, 4}, {0, 5}, {6, 4}, {6, 9}, {7, 6}};
double weight[15] = { 0.0 };
EdgeWeightedDigraph digraph(13, 15, arr, weight);
DepthFirstOrder dfs(&digraph);
queue<int> pre = dfs.getPreOrder();
queue<int> post = dfs.getPostOrder();
stack<int> reverse = dfs.getReversePostOrder();
cout << "v pre post" << endl;
for (int i = 0; i < 13; ++i)
cout << i << " " << dfs.getPre(i) << " " << dfs.getPost(i) << endl;
cout << "previous order :" << endl;
while (!pre.empty())
{
cout << pre.front() << " " ;
pre.pop();
}
cout << endl;
cout << "post order :" << endl;
while (!post.empty())
{
cout << post.front() << " " ;
post.pop();
}
cout << endl;
cout << "reverse post oder :" << endl;
while (!reverse.empty())
{
cout << reverse.top() << " " ;
reverse.pop();
}
cout << endl;
test2:
int arr[][2] = {{0, 1}, {0, 2}, {1, 3},
{1, 4}, {3, 7}, {4, 7},
{2, 5}, {5, 6}, {6, 2}};
double weight[9] = { 0.0 };
EdgeWeightedDigraph digraph(8, 9, arr, weight);
EdgeWeightedDirectedCycle detectcycle(&digraph);
stack<DirectedEdge *> cycle = detectcycle.getCycle();
while (!cycle.empty())
{
DirectedEdge *e = cycle.top();
cout << e->from() << " ---> " << e->to() << endl;
cycle.pop();
}
cout << endl;
*/
int arr[][2] = {{5, 4}, {4, 7}, {5, 7}, {5, 1}, {4, 0},
{0, 2}, {3, 7}, {1, 3}, {7, 2}, {6, 2},
{3, 6}, {6, 0}, {6, 4}};
double weight[13] = {0.35, 0.37, 0.28, 0.32, 0.38,
0.26, 0.39, 0.29, 0.34, 0.40,
0.52, 0.58, 0.93 };
EdgeWeightedDigraph digraph(8, 13, arr, weight);
int s = 5;
AcyclicSP sp(&digraph, s);
for (int t = 0; t < 8; ++t)
if (sp.hasPathTo(t))
{
cout << s << " to " << t << " (" << sp.getDistTo(t) << ")" << endl;
stack<DirectedEdge *> path = sp.pathTo(t);
while (!path.empty())
{
DirectedEdge *e = path.top();
cout << e->toString();
path.pop();
}
}
else
cout << s << " to " << t << " has no path" << endl;
return 0;
}
output:
5 to 0 (0.73)
5 -- 4: 0.35
4 -- 0: 0.38
5 to 1 (0.32)
5 -- 1: 0.32
5 to 2 (0.62)
5 -- 7: 0.28
7 -- 2: 0.34
5 to 3 (0.61)
5 -- 1: 0.32
1 -- 3: 0.29
5 to 4 (0.35)
5 -- 4: 0.35
5 to 5 (0)
5 to 6 (1.13)
5 -- 1: 0.32
1 -- 3: 0.29
3 -- 6: 0.52
5 to 7 (0.28)
5 -- 7: 0.28