网络流24题(十一)

网络流24题(十一)

十一、航空路线问题

题目描述

给定一张航空图,图中顶点代表城市,边代表两城市间的直通航线,并且不存在任何两个城市在同一条经线上。现要求找出一条满足下述限制条件的且途经城市最多的旅行路线。

  1. 从最西端城市出发,单向从西向东途经若干城市到达最东端城市,然后再单向从东向西飞回起点(可途经若干城市)。

  2. 除起点城市外,任何城市只能访问一次。

对于给定的航空图,试设计一个算法找出一条满足要求的最佳航空旅行路线。

输入格式

输入的第一行是用空格隔开的两个整数,分别代表航空图的点数 \(n\) 和边数 \(v\)

\(2\) 到第 \((n + 1)\) 行,每行一个字符串,第 \((i + 1)\) 行的字符串代表从西向东第 \(i\) 座城市的名字 \(s_i\)

\((n + 2)\) 到第 \((n + v + 1)\) 行,每行两个字符串 \(x, y\)代表城市 \(x\) 和城市 \(y\) 之间存在一条直通航线。

输出格式

本题存在 Special Judge

请首先判断是否存在满足要求的路线,若存在,请给出一种旅行的方案。

如果存在路线,输出格式为:

  • 请在第一行输出一个整数 \(m\),代表途径最多的城市数。
  • 在第 2 到第 \((m + 1)\) 行,每行一个字符串,第 \((i + 1)\) 行的字符串代表旅行路线第 \(i\) 个经过的城市的名字。请注意第 \(1\) 和第 \(m\) 个城市必然是出发城市名。

否则请输出一行一个字符串 No Solution!

题解

模型:

费用流、拆点、输出方案
双路\(DP\)

建图与实现:

只有两条路径,想到限制流为2。
每一个点都有限制,即只能选一次,选了之后得分加一,所以想到拆点限制点的容量。
对于一个点\(i\),拆成\(i\)\(i+n\),容量为一,费用为1。但特殊点起点与终点会出现两次(题面说起点可以有多次,但是想一下在最大流上限为2的情况下,最多也只有两次)。但是这时候多的不加费用,所以再加上一条容量为1,费用为0的边。
最后在题目给出的图上的边,限制为容量无穷,费用为0。
最后跑最大费用最大流,如果得到的流小于2,说明没有两条路径,输出 No Solution!
输出方案比较恶心,但不算很难(好吧我承认我wa在这)。

代码

#include <iostream>
#include <queue>
#include <cstring>
#include <map>
#include <stack>
#define ll long long

const ll N = 5e3+50,M = 5e4+50;
const ll inf = 0x3f3f3f3f;
using namespace std;
ll head[N],cnt = 1;
//将EK的bfs变为spfa
struct Edge{
    ll to,w,cost,nxt;
}edge[M*2];
void add(ll u,ll v,ll w,ll c){
    edge[++cnt] = {v,w,c,head[u]};
    head[u] = cnt;
}
void  add2(ll u,ll v,ll w,ll cost){
    add(u,v,w,cost);
    add(v,u,0,-cost);
}
ll s,t,dis[N],cur[N];
bool inq[N],vis[N];
queue<ll>Q;
bool spfa(){
    while(!Q.empty()) Q.pop();
    copy(head,head+N,cur);
    fill(dis,dis+N,inf);
    dis[s] = 0;
    Q.push(s);
    while(!Q.empty()){
        ll p = Q.front();
        Q.pop();
        inq[p] = false;
        for(ll e = head[p];e;e = edge[e].nxt){
            ll to = edge[e].to,vol = edge[e].w;
            if(vol > 0 && dis[to]>dis[p]+edge[e].cost){
                dis[to] = dis[p] + edge[e].cost;
                if(!inq[to]){
                    Q.push(to);
                    inq[to] = true;
                }
            }
        }
    }
    return dis[t] != inf;
}
ll dfs(ll p = s,ll flow = inf){
    if(p == t) return flow;
    vis[p] = true;
    ll rmn = flow;
    for(ll eg = cur[p];eg && rmn;eg = edge[eg].nxt){
        cur[p] = eg;
        ll to = edge[eg].to,vol = edge[eg].w;
        if(vol > 0 && !vis[to]&&dis[to] == dis[p]+edge[eg].cost){
            ll c = dfs(to,min(vol,rmn));
            rmn -= c;
            edge[eg].w -= c;
            edge[eg^1].w += c;
        }
    }
    vis[p] = false;
    return flow-rmn;
}
ll maxflow = 0,mincost = 0;
void dinic(){
    while(spfa()){
        ll flow = dfs();
        maxflow += flow;
        mincost += dis[t]*flow;
    }
}
ll n,m;
string city[N];
map<string,ll> num;
queue<ll>tour1;
stack<ll>tour2;
bool inTr[N];
void find1(ll x){
    for(ll eg = head[x+n];eg;eg = edge[eg].nxt){
        ll to = edge[eg].to,vol = edge[eg].w;
        if(vol == inf) continue;
        if(inTr[to])continue;
        for(ll j = head[to];j;j = edge[j].nxt){
            if(edge[j].w == 0 && edge[j].to == to+n){
                tour1.push(to);
                inTr[to] = true;
                find1(to);
                return;
            }
        }
    }
}
void find2(ll x){
    for(ll eg = head[x+n];eg;eg = edge[eg].nxt){
        ll to = edge[eg].to,vol = edge[eg].w;
        if(vol == inf) continue;
        if(inTr[to])continue;
        for(ll j = head[to];j;j = edge[j].nxt){
            if(edge[j].w == 0 && edge[j].to == to+n){
                tour2.push(to);
                inTr[to] = true;
                find2(to);
                return;
            }
        }
    }
}
void print(){
    inTr[1] = true;
    find1(1);
    find2(1);
    cout<<city[1]<<endl;
    while(!tour1.empty()){
        ll x = tour1.front();
        tour1.pop();
        cout<<city[x]<<endl;
    }
    while(!tour2.empty()){
        ll x = tour2.top();
        tour2.pop();
        cout<<city[x]<<endl;
    }
    cout<<city[1]<<endl;
}
int main() {
    cin>>n>>m;
    for(ll i = 1;i <= n;i++){
        cin>>city[i];
        num[city[i]] = i;
    }
    while(m--){
        string x,y;cin>>x>>y;
        ll u = num[x],v = num[y];
        //cout<<u<<' '<<v<<endl;
        add2(u+n,v,inf,0);
    }
    s = 1,t = 2*n;
    add2(1,n+1,1,-1);
    add2(1,n+1,1,0);
    add2(n,n+n,1,-1);
    add2(n,n+n,1,0);
    for(ll i = 2;i < n;i++) add2(i,i+n,1,-1);

    dinic();
//    cout<<maxflow<<' '<<mincost<<endl;
//    if(mincost == -4){
//        cout<<city[1]<<endl<<city[n]<<endl<<city[1]<<endl;
//    }
    if(maxflow != 2) {
        puts("No Solution!");
        return 0;
    }
    cout<<-1*mincost<<endl;
    print();
    return 0;
}

posted @ 2021-10-05 11:18  Paranoid5  阅读(34)  评论(0编辑  收藏  举报