1. 程式人生 > 其它 >網路流24題(十一)

網路流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;
}