单源最短路径---Bellman-Ford

Bellman-ford算法是求解连通带权图中单源最短路径的一种常用算法,它允许图中存在权值为负的边。
同时它还能够判断出图中是否存在一个权值之和为负的回路。如果存在的话,图中就不存在最短路径。
判断是否存在从源点可达的负权值回路的方法,在求出最终的distTo[]之后,在对每一条边<u,v>判断一下,
加入这条边是否会使得结点v的最短路径在缩短,即判断 distTo[u]+w(u,v)<distTo[v],如果小于,则说明
存在负权回路。

《单源最短路径---Bellman-Ford》

《单源最短路径---Bellman-Ford》

(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

 

    原文作者:Bellman - ford算法
    原文地址: https://blog.csdn.net/cai0612123/article/details/38065723
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞