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\n", e->From->Id, e->To->Id, e->Cost*minFlow, e->Cap);
#endif
            }
#ifdef test
            printf("TotFlow %d TotCost %d\n", 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\n", -g.TotCost-2);
    LOOP(v, g._vCount)
        g._nodes[v].Inq = false;
    print1();
    print2(1);
    return 0;
}

 

转载于:https://www.cnblogs.com/headboy2002/p/8431179.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值