Bellman-ford算法是求解连通带权图中单源最短路径的一种常用算法,它允许图中存在权值为负的边。
同时它还能够判断出图中是否存在一个权值之和为负的回路。如果存在的话,图中就不存在最短路径。
判断是否存在从源点可达的负权值回路的方法,在求出最终的distTo[]之后,在对每一条边<u,v>判断一下,
加入这条边是否会使得结点v的最短路径在缩短,即判断 distTo[u]+w(u,v)<distTo[v],如果小于,则说明
存在负权回路。
(1)Bellman-Ford algorithm. Initialize distTo[s] to 0 and all other distTo[] values to infinity. Then, considering the digraph's edges in any order, and relax all edges. Make V such passes.
for (int pass = 0; pass < G.V(); pass++)
for (int v = 0; v < G.V(); v++)
for (DirectedEdge e : G.adj(v))
relax(e);
We do not consider this version in detail because it always relaxes V E edges.
(2)Queue-based Bellman-Ford algorithm. The only edges that could lead to a change in distTo[] are those leaving a vertex whose distTo[] value changed in the previous pass. To keep track of such vertices, we use a FIFO queue. BellmanFordSP implements this approach by maintaining two additional data structures:
a.A queue of vertices to be relaxed
b.A vertex-index boolean array onQ[] that indicates which vertices are on the queue,
to avoid duplicates
#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(int nVertex);
~EdgeWeightedDigraph();
list<DirectedEdge *> getAdj(int v);
list<DirectedEdge *> edges();
int getV() { return V; }
void addEdge(DirectedEdge *);
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(int nVertex)
{
V = nVertex;
E = 0;
adj = new list<DirectedEdge *>[nVertex];
}
EdgeWeightedDigraph::~EdgeWeightedDigraph()
{
list<DirectedEdge *> ls = edges();
for (list<DirectedEdge *>::iterator it = ls.begin(); it != ls.end(); ++it)
{
if (NULL != (*it))
{
delete *it;
*it = NULL;
}
}
if (NULL != adj)
{
delete []adj;
adj = NULL;
}
}
list<DirectedEdge *> EdgeWeightedDigraph::getAdj(int v)
{
if (v >= 0 && v < V)
return adj[v];
}
void EdgeWeightedDigraph::addEdge(DirectedEdge *e)
{
adj[e->from()].push_back(e);
++E;
}
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;
}
class BellmanFordSP
{
public:
BellmanFordSP(EdgeWeightedDigraph *g, int s);
~BellmanFordSP();
bool hasNegativeCycle() { return (cycle.empty() ? false : true); }
double getDistTo(int v) { return distTo[v]; }
bool hasPathTo(int v) { return distTo[v] < MAX; }
stack<DirectedEdge *> pathTo(int v);
stack<DirectedEdge *> getCycle() { return cycle; }
private:
void relax(EdgeWeightedDigraph *g, int v);
void findNegativeCycle(EdgeWeightedDigraph *g);
private:
double *distTo; // distTo[v] = distance of shortest s->v path
DirectedEdge **edgeTo; // edgeTo[v] = last edge on shortest s->v path
bool *onQueue; // onQueue[v] = is v currently on the queue?
queue<int> qrelax; // queue of vertices to relax
int cost; // number of calls to relax
stack<DirectedEdge *> cycle; // negative cycle
};
BellmanFordSP::BellmanFordSP(EdgeWeightedDigraph *g, int s)
{
cost = 0;
int v = g->getV();
distTo = new double[v];
edgeTo = new DirectedEdge *[v];
onQueue = new bool[v];
for (int i = 0; i < v; ++i)
{
distTo[i] = MAX;
edgeTo[i] = NULL;
onQueue[i] = false;
}
distTo[s] = 0.0;
qrelax.push(s);
onQueue[s] = true;
while (!qrelax.empty() && !hasNegativeCycle())
{
int t = qrelax.front();
qrelax.pop();
onQueue[t] = false;
relax(g, t);
}
}
BellmanFordSP::~BellmanFordSP()
{
if (NULL != distTo)
{
delete []distTo;
distTo = NULL;
}
if (NULL != edgeTo)
{
delete []edgeTo;
edgeTo = NULL;
}
if (NULL != onQueue)
{
delete []onQueue;
onQueue = NULL;
}
}
// relax vertex v and put other endpoints on queue if changed
void BellmanFordSP::relax(EdgeWeightedDigraph *g, int v)
{
list<DirectedEdge *> ls = g->getAdj(v);
for (list<DirectedEdge *>::iterator it = ls.begin(); it != ls.end(); ++it)
{
int w = (*it)->to();
double t = distTo[v] + (*it)->getWeight();
if (distTo[w] > t)
{
distTo[w] = t;
edgeTo[w] = *it;
if (!onQueue[w])
{
onQueue[w] = true;
qrelax.push(w);
}
}
if (0 == cost++ % (g->getV()))
findNegativeCycle(g);
}
}
void BellmanFordSP::findNegativeCycle(EdgeWeightedDigraph *g)
{
int v = g->getV();
EdgeWeightedDigraph spt(v);
for (int i = 0; i < v; ++i)
if (NULL != edgeTo[i])
{
DirectedEdge *e = new DirectedEdge(edgeTo[i]->from(), edgeTo[i]->to(), edgeTo[i]->getWeight());
spt.addEdge(e);
}
EdgeWeightedDirectedCycle finder(&spt);
cycle = finder.getCycle();
}
stack<DirectedEdge *> BellmanFordSP::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()
{
int arr[][2] = {{4, 5}, {5, 4}, {4, 7}, {5, 7}, {7, 5},
{5, 1}, {0, 4}, {0, 2}, {7, 3}, {1, 3},
{2, 7}, {6, 2}, {3, 6}, {6, 0}, {6, 4}};
double weight[15] = {0.35, 0.35, 0.37, 0.28, 0.28,
0.32, 0.38, 0.26, 0.39, 0.29,
0.34, -1.20, 0.52, -1.40, -1.25};
EdgeWeightedDigraph digraph(8, 15, arr, weight);
int s = 0;
BellmanFordSP sp(&digraph, s);
if (sp.hasNegativeCycle())
{
stack<DirectedEdge *> cycle = sp.getCycle();
while (!cycle.empty())
{
DirectedEdge *e = cycle.top();
cycle.pop();
cout << e->toString() << endl;
}
}
else
{
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:
0 to 0 (0)
0 to 1 (0.93)
0 -- 2: 0.26
2 -- 7: 0.34
7 -- 3: 0.39
3 -- 6: 0.52
6 -- 4: -1.25
4 -- 5: 0.35
5 -- 1: 0.32
0 to 2 (0.26)
0 -- 2: 0.26
0 to 3 (0.99)
0 -- 2: 0.26
2 -- 7: 0.34
7 -- 3: 0.39
0 to 4 (0.26)
0 -- 2: 0.26
2 -- 7: 0.34
7 -- 3: 0.39
3 -- 6: 0.52
6 -- 4: -1.25
0 to 5 (0.61)
0 -- 2: 0.26
2 -- 7: 0.34
7 -- 3: 0.39
3 -- 6: 0.52
6 -- 4: -1.25
4 -- 5: 0.35
0 to 6 (1.51)
0 -- 2: 0.26
2 -- 7: 0.34
7 -- 3: 0.39
3 -- 6: 0.52
0 to 7 (0.6)
0 -- 2: 0.26
2 -- 7: 0.34