zoukankan      html  css  js  c++  java
  • POJ3255 Roadblocks 严格次短路

    题目大意:求图的严格次短路。

    方法1:

    SPFA,同时求单源最短路径和单源次短路径。站在节点u上放松与其向量的v的次短路径时时,先尝试由u的最短路径放松,再尝试由u的次短路径放松(该两步并非非此即彼)。

    由u的最短路径放松:

    if(u->Dist + e->Weight < v->Dist)
        v->Dist2=v->Dist;
      //此处隐藏最短路放松。次短路不在此固定,Dist2可能在由u次短路放松时被放松得更短
    
    if(u->Dist + e->Weight > v->Dist && u->Dist + e->Weight < v->Dist2)
        v->Dist2=u->Dist+e->Weight;

    由u的次短路经放松:

    if(u->Dist2 + e->Weight > v->Dist && u->Dist2 + e->Weight < v->Dist2)
        v->Dist2=u->Dist2 + e->Weight;

    完整代码:

    #include <cstdio>
    #include <cstring>
    #include <cassert>
    #include <queue>
    using namespace std;
    
    #define LOOP(i,n) for(int i=1; i<=n; i++)
    const int MAX_NODE = 5010, MAX_EDGE = 100010 * 2, INF = 0x3f3f3f3f;
    
    struct Node;
    struct Edge;
    
    struct Node
    {
        int Id, Dist, Dist2;
        bool Inq;
        Edge *Head;
    }_nodes[MAX_NODE], *Start, *Target;
    int _vCount;
    
    struct Edge
    {
        int Weight;
        Node *From, *To;
        Edge *Next;
        Edge() {}
        Edge(Node *from, Node *to, Edge *next, int weight) :
            From(from), To(to), Next(next), Weight(weight){}
    }*_edges[MAX_EDGE];
    int _eCount;
    
    void Init(int vCount)
    {
        memset(_nodes, 0, sizeof(_nodes));
        _vCount = vCount;
        _eCount = 0;
        Start = 1 + _nodes;
        Target = vCount + _nodes;
    }
    
    void AddEdge(Node *from, Node *to, int weight)
    {
        Edge *e = _edges[++_eCount] = new Edge(from, to, from->Head, weight);
        e->From->Head = e;
    }
    
    void Build(int uId, int vId, int weight)
    {
        Node *u = uId + _nodes, *v = vId + _nodes;
        u->Id = uId;
        v->Id = vId;
        AddEdge(u, v, weight);
        AddEdge(v, u, weight);
    }
    
    void SPFA()
    {
        LOOP(i, _vCount)
            _nodes[i].Dist = _nodes[i].Dist2 = INF;
        static queue<Node*> q;
        Start->Dist = 0;
        Start->Dist2 = INF;
        Start->Inq = true;
        q.push(Start);
        while (!q.empty())
        {
            Node *u = q.front();
            q.pop();
            u->Inq = false;
            for (Edge *e = u->Head; e; e = e->Next)
            {
                bool relaxOk = false;
                if (u->Dist + e->Weight < e->To->Dist)
                {
                    e->To->Dist2 = e->To->Dist;
                    e->To->Dist = u->Dist + e->Weight;
                    relaxOk = true;
                }
                else if (u->Dist + e->Weight > e->To->Dist && u->Dist + e->Weight < e->To->Dist2)
                {
                    e->To->Dist2 = u->Dist + e->Weight;
                    relaxOk = true;
                }
                if (u->Dist2 + e->Weight < e->To->Dist2)
                {
                    e->To->Dist2 = u->Dist2 + e->Weight;
                    relaxOk = true;
                }
                if (relaxOk && !e->To->Inq)
                {
                    e->To->Inq = true;
                    q.push(e->To);
                }
            }
        }
    }
    
    int main()
    {
    #ifdef _DEBUG
        freopen("c:\noi\source\input.txt", "r", stdin);
    #endif
        int testCase, totNode, totEdge, uId, vId, weight, sId, tId;
        scanf("%d%d", &totNode, &totEdge);
        Init(totNode);
        LOOP(i, totEdge)
        {
            scanf("%d%d%d", &uId, &vId, &weight);
            Build(uId, vId, weight);
        }
        SPFA();
        printf("%d
    ", Target->Dist2);
        return 0;
    }
    View Code

    方法2:

    Dijkstra。其需用到优先队列,维护一对数据:一个节点u以及它到原点的路径d。d可以是u的最短路径,也可以是u的次短路径,但我们不用管它,我们只管放松。它能放松v最短路就放松v最短路,再不行看看它能不能放松v次短路。

    完整代码:

    #include <cstdio>
    #include <cstring>
    #include <cassert>
    #include <queue>
    #include <vector>
    #include <functional>
    using namespace std;
    
    #define LOOP(i,n) for(int i=1; i<=n; i++)
    const int MAX_NODE = 5010, MAX_EDGE = 100010 * 2, INF = 0x3f3f3f3f;
    
    struct Node;
    struct Edge;
    
    struct Node
    {
        int Id, Dist, Dist2;
        bool Inq;
        Edge *Head;
    }_nodes[MAX_NODE], *Start, *Target;
    int _vCount;
    
    struct Edge
    {
        int Weight;
        Node *From, *To;
        Edge *Next;
        Edge() {}
        Edge(Node *from, Node *to, Edge *next, int weight) :
            From(from), To(to), Next(next), Weight(weight) {}
    }*_edges[MAX_EDGE];
    int _eCount;
    
    void Init(int vCount)
    {
        memset(_nodes, 0, sizeof(_nodes));
        _vCount = vCount;
        _eCount = 0;
        Start = 1 + _nodes;
        Target = vCount + _nodes;
    }
    
    void AddEdge(Node *from, Node *to, int weight)
    {
        Edge *e = _edges[++_eCount] = new Edge(from, to, from->Head, weight);
        e->From->Head = e;
    }
    
    void Build(int uId, int vId, int weight)
    {
        Node *u = uId + _nodes, *v = vId + _nodes;
        u->Id = uId;
        v->Id = vId;
        AddEdge(u, v, weight);
        AddEdge(v, u, weight);
    }
    
    #define Pair pair<int,Node*>
    void Dijkstra()
    {
        static priority_queue<Pair, vector<Pair>, greater<Pair>> q;
        LOOP(i, _vCount)
            _nodes[i].Dist = _nodes[i].Dist2 = INF;
        Start->Dist = 0;
        q.push(Pair(0, Start));
        while (!q.empty())
        {
            Pair cur = q.top();
            q.pop();
            Node *u = cur.second;
            int prevDist = cur.first;
            //printf("prevDist %d
    ", prevDist);
            assert(prevDist >= u->Dist);
            for (Edge *e = u->Head; e; e = e->Next)
            {
                if (prevDist + e->Weight < e->To->Dist)
                {
                    e->To->Dist2 = e->To->Dist;
                    e->To->Dist = prevDist + e->Weight;
                    q.push(Pair(e->To->Dist, e->To));
                }
                else if (e->To->Dist < prevDist+e->Weight
                    &&prevDist+e->Weight < e->To->Dist2)
                {
                    e->To->Dist2 = prevDist + e->Weight;
                    q.push(Pair(e->To->Dist2, e->To));
                }
            }
        }
    }
    
    int main()
    {
    #ifdef _DEBUG
        freopen("c:\noi\source\input.txt", "r", stdin);
    #endif
        int testCase, totNode, totEdge, uId, vId, weight, sId, tId;
        scanf("%d%d", &totNode, &totEdge);
        Init(totNode);
        LOOP(i, totEdge)
        {
            scanf("%d%d%d", &uId, &vId, &weight);
            Build(uId, vId, weight);
        }
        Dijkstra();
        printf("%d
    ", Target->Dist2);
        return 0;
    }
    View Code

    方法3:

    我们假设一条边e在次短路径内,知道这条次短路径长度d[e]是多少。那么,我们枚举每个e,求出min{d[e]}即可。具体我们需要求出每一个节点到原点的最短路径和到汇点的最短路径。这样,d[e]=e->From->DistS + e->Weight + e->To->DistT。这样求出的d[e]可能与最短路径相等。此时怎样把它转化成次短路?只能将e重复走一遍!这样,d[e]'=e->From->DistS + e->Weight * 2 + e->From->DistT。

    完整代码:

    #include <cstdio>
    #include <cstring>
    #include <cassert>
    #include <queue>
    #include <vector>
    #include <functional>
    using namespace std;
    
    #define LOOP(i,n) for(int i=1; i<=n; i++)
    const int MAX_NODE = 5010, MAX_EDGE = 100010 * 2, INF = 0x3f3f3f3f;
    
    struct Node;
    struct Edge;
    
    struct Node
    {
        int Id, Dist, Dist2;
        bool Inq;
        Edge *Head;
    }_nodes[MAX_NODE], *Start, *Target;
    int _vCount;
    
    struct Edge
    {
        int Weight;
        Node *From, *To;
        Edge *Next;
        Edge() {}
        Edge(Node *from, Node *to, Edge *next, int weight) :
            From(from), To(to), Next(next), Weight(weight) {}
    }*_edges[MAX_EDGE];
    int _eCount;
    
    void Init(int vCount)
    {
        memset(_nodes, 0, sizeof(_nodes));
        _vCount = vCount;
        _eCount = 0;
        Start = 1 + _nodes;
        Target = vCount + _nodes;
    }
    
    void AddEdge(Node *from, Node *to, int weight)
    {
        Edge *e = _edges[++_eCount] = new Edge(from, to, from->Head, weight);
        e->From->Head = e;
    }
    
    void Build(int uId, int vId, int weight)
    {
        Node *u = uId + _nodes, *v = vId + _nodes;
        u->Id = uId;
        v->Id = vId;
        AddEdge(u, v, weight);
        AddEdge(v, u, weight);
    }
    
    void SPFA(Node *start)
    {
        LOOP(i, _vCount)
        {
            _nodes[i].Dist = INF;
            _nodes[i].Inq = false;
        }
        static queue<Node*> q;
        start->Dist = 0;
        start->Inq = true;
        q.push(start);
        while (!q.empty())
        {
            Node *u = q.front();
            q.pop();
            u->Inq = false;
            for (Edge *e = u->Head; e; e = e->Next)
            {
                if (u->Dist + e->Weight < e->To->Dist)
                {
                    e->To->Dist = u->Dist + e->Weight;
                    if (!e->To->Inq)
                    {
                        e->To->Inq = true;
                        q.push(e->To);
                    }
                }
            }
        }
    }
    
    int Proceed()
    {
        SPFA(Target);
        int minDist = Start->Dist, ans = INF;
        LOOP(i, _vCount)
            _nodes[i].Dist2 = _nodes[i].Dist;
        SPFA(Start);
        LOOP(i, _eCount)
        {
            Edge *e = _edges[i];
            int temp = e->From->Dist + e->Weight + e->To->Dist2;
            if (minDist < temp&&temp < ans)
                ans = temp;
            else
            {
                temp = e->From->Dist + e->From->Dist2 + e->Weight * 2;
                ans = min(ans, temp);
            }
        }
        return ans;
    }
    
    int main()
    {
    #ifdef _DEBUG
        freopen("c:\noi\source\input.txt", "r", stdin);
    #endif
        int testCase, totNode, totEdge, uId, vId, weight, sId, tId;
        scanf("%d%d", &totNode, &totEdge);
        Init(totNode);
        LOOP(i, totEdge)
        {
            scanf("%d%d%d", &uId, &vId, &weight);
            Build(uId, vId, weight);
        }
        printf("%d
    ", Proceed());
        return 0;
    }
    View Code
  • 相关阅读:
    今日小结
    Delphi 框架Frames的使用
    Delphi窗体显示后弹出一个对话框的方法
    Structs2学习笔记1
    使用 LaravelExcel 进行 CSV/EXCEL 文件读写
    Mysql函数FIND_IN_SET()的使用方法
    Laravel数据库操作的三种方式
    Laravel5.5 支付宝手机网站支付的教程
    Python之路3【知识点】白话Python编码和文件操作
    艾伟_转载:利用jQuery实现的Ajax 验证用户名是否存在 狼人:
  • 原文地址:https://www.cnblogs.com/headboy2002/p/8457828.html
Copyright © 2011-2022 走看看