有向无环图的单源最短路径----拓扑排序+松弛


算法开始对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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值