• luogu2770 航空路线问题 网络流


    题目大意:

    给定一张航空图,图中顶点代表城市,边代表 2 城市间的直通航线。现要求找出一条满足下述限制条件的且途经城市最多的旅行路线。
    (1)从最西端城市出发,单向从西向东途经若干城市到达最东端城市,然后再单向从东向西飞回起点(可途经若干城市)。
    (2)除起点城市外,任何城市只能访问 1 次。

    关键字:网络流 方向等效转换 拆点 不交叉路径 特判

    网络流:1个人旅行的过程可以看作以流量为1流动的过程。

    方向等效转化:本问题可以看作两个人同时从最西的城市走向最东的城市,每个人占有1个流量,总流量为2。

    拆点:题中说每个城市只经过一次,因此把一个城市看作容量为1的边,如果西东两个城市之间有航线,则把西城to节点连东城from节点,容量为1。为保证总流量为2,最西城边容量和最东城容量为2。

    不交叉路径:流量为1,即可保证路径不交叉

    特判:如果最西城与最东城有航线,则边的容量为2。

    #include <cstdio>
    #include <cstring>
    #include <queue>
    #include <cmath>
    #include <cassert>
    #include <map>
    #include <string>
    #include <iostream>
    using namespace std;
    
    //#define test
    #define INF 0x3f3f3f3f
    #define LOOP(i,n) for(int i=1; i<=n; i++)
    const int MAX_CITY = 110, MAX_EDGE = MAX_CITY*MAX_CITY + MAX_CITY * 2, MAX_NODE = MAX_CITY * 2;
    map<string, int> loc;
    string Cities[MAX_CITY];
    bool Vis[MAX_CITY];
    int TotCity, TotLine;
    
    struct MCMF
    {
        struct Node;
        struct Edge;
    
        struct Node
        {
            int Id;
            Edge *Head, *Prev;
            int Dist;
            bool Inq;
    
            void Init()
            {
                Prev = NULL;
                Dist = INF;
                Inq = false;
            }
        };
    
        struct Edge
        {
            int Cap, Cost;
            Node *From, *To;
            Edge *Next, *Rev;
            Edge(int cap, int cost, Node *from, Node *to, Edge *next) :Cap(cap), Cost(cost), From(from), To(to), Next(next){}
        };
    
    
        Node _nodes[MAX_NODE];
        Edge *_edges[MAX_EDGE];
        int _vCount = 0, _eCount = 0;
        Node *Start, *Sink;
        int TotFlow, TotCost;
    
        void Reset(int n, int sId, int tId)
        {
            _vCount = n;
            _eCount = 0;
            Start = &_nodes[sId], Sink = &_nodes[tId];
            TotFlow = TotCost = 0;
        }
    
        Edge* AddEdge(Node *from, Node *to, int cap, int cost)
        {
            Edge *cur = _edges[++_eCount] = new Edge(cap, cost, from, to, from->Head);
            from->Head = cur;
            return cur;
        }
    
        void Build(int uId, int vId, int cap, int cost)
        {
            Node *u = &_nodes[uId], *v = &_nodes[vId];
            u->Id = uId;
            v->Id = vId;
            Edge *edge1 = AddEdge(u, v, cap, cost);
            Edge *edge2 = AddEdge(v, u, 0, -cost);//遗忘点*2:-cost
            edge1->Rev = edge2;
            edge2->Rev = edge1;
        }
    
        bool SPFA()
        {
            queue<Node*> q;
            for (int i = 1; i <= _vCount; i++)
                _nodes[i].Init();
            Start->Dist = 0;
            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 (e->Cap && u->Dist + e->Cost < e->To->Dist)//易忘点*2:e->Cap
                    {
                        e->To->Dist = u->Dist + e->Cost;
                        e->To->Prev = e;
                        if (!e->To->Inq)
                        {
                            e->To->Inq = true;
                            q.push(e->To);
                        }
                    }
                }
            }
            return Sink->Prev;
        }
    
        void Proceed()
        {
            while (SPFA())
            {
                assert(Sink->Dist != INF);
                int minFlow = INF;
                for (Edge *e = Sink->Prev; e; e = e->From->Prev)
                    minFlow = min(minFlow, e->Cap);
                TotFlow += minFlow;
                for (Edge *e = Sink->Prev; e; e = e->From->Prev)
                {
                    e->Cap -= minFlow;
                    e->Rev->Cap += minFlow;
                    TotCost += minFlow * e->Cost;
    #ifdef test
                    printf("%d-%d Cost %d restCap %d
    ", e->From->Id, e->To->Id, e->Cost*minFlow, e->Cap);
    #endif
                }
    #ifdef test
                printf("TotFlow %d TotCost %d
    ", TotFlow, TotCost);
    #endif
            }
        }
    
        int GetFlow()
        {
            return TotFlow;
        }
    
        int GetCost()
        {
            return TotCost;
        }
    }g;
    
    void print1()
    {
        MCMF::Node *cur = 1 + g._nodes;
        while (cur->Id != TotCity)
        {
            Vis[cur->Id] = true;
            cout << Cities[cur->Id] << endl;
            cur = cur->Id + TotCity + g._nodes;
            for (MCMF::Edge *e = cur->Head; e; e = e->Next)
            {
                if (!e->Cap && !Vis[e->To->Id] && e->To->Id > cur->Id-TotCity)
                {
                    cur = e->To;
                    break;
                }
            }
        }
    }
    
    void print2(int id)
    {
        if (id == TotCity)
        {
            cout << Cities[id] << endl;
            return;
        }
        Vis[id] = true;
        MCMF::Node *cur = id + TotCity + g._nodes;
        for (MCMF::Edge *e = cur->Head; e; e = e->Next)
        {
            if (!e->Cap && !Vis[e->To->Id] && e->To->Id > cur->Id - TotCity)
            {
                print2(e->To->Id);
                break;
            }
        }
        cout << Cities[id] << endl;
    }
    
    int main()
    {
    #ifdef _DEBUG
        freopen("c:\noi\source\input.txt", "r", stdin);
    #endif
        int sId, tId;
        string s1, s2;
        scanf("%d%d", &TotCity, &TotLine);
        sId = 1;
        tId = TotCity * 2;
        g.Reset(tId, sId, tId);
        LOOP(city, TotCity)
        {
            cin >> Cities[city];
            loc.insert(pair<string, int>(Cities[city], city));
            if (city == 1 || city == TotCity)
                g.Build(city, city + TotCity, 2, -1);
            else
                g.Build(city, city + TotCity, 1, -1);
        }
        LOOP(line, TotLine)
        {
            cin >> s1 >> s2;
            int p1 = loc[s1], p2 = loc[s2];
            if (p2 < p1)
                swap(p1, p2);
            if (p1 == 1 && p2 == TotCity)
                g.Build(p1+TotCity, p2, 2, 0);
            else
                g.Build(p1+TotCity, p2, 1, 0);
        }
        g.Proceed();
        if (g.TotFlow<2)
        {
            cout << "No Solution!" << endl;
            return 0;
        }
        printf("%d
    ", -g.TotCost-2);
        LOOP(v, g._vCount)
            g._nodes[v].Inq = false;
        print1();
        print2(1);
        return 0;
    }
  • 相关阅读:
    Ubuntu+XAMPP+Wordpress的安装与配置问题
    Html5最简单的游戏Demo——Canvas绘图的骰子
    Html5最简单的游戏Demo——Canvas绘图的弹弹球
    LinqToExcel: LINQ查询Excel电子表格
    Asp.Net Web API开发微信后台
    Json.Net使用JSON Schema验证JSON格式【实例】
    Json.Net使用JSON Schema验证JSON格式
    LeetCode-C#实现-哈希表(#349)
    大话设计模式-解释器模式
    大话设计模式-享元模式
  • 原文地址:https://www.cnblogs.com/headboy2002/p/8431179.html
Copyright © 2020-2023  润新知