航空路线问题

航空路线问题

做的第三道二十四题qwq,

前两道都没发 \(blog\) .

原因是一道太水了(裸二分图最大匹配),

还有一道一会再写qwq(虽然过了好久了).

这道题是某 HwH 聚神随机跳题跳到的,

鉴于我学网络流比他有经验(bushi),

于是乎他便来找我qwq,

但是由于当时刚好该放学了(其实是因为我在搞事system),

我就随便一看,

结果发现是道水题bushi,

然后秒了qwq.

这道题其实非常简单(不知道为什么评紫?!),

首先,

因为我们一去一回,

所以就相当于去两趟,

但是要走不同的路.

所以我们从源点(可以是 \(1\) 也可以再开一个点)建一条容量为 \(2\) 的边,

这不就好起来了?

然后正常建边,

每条边的容量和费用都为 \(1\) ,

跑一边最大费用最大流就好了.

于是我发现我 \(WA\) 了(真不戳).

后来发现要拆点,

因为每个城市只能走一次.

ok, very good!

这下好了,

全都是unexpected order.

怎么多输出了一个 "No Solution!" ?

然后又双叒叕读了一遍题,

发现无解的情况并非是无法回来(最大流为 \(1\)),

而是无法到达(最大流为 \(0\)).

然后就ok了,

只差顺序了.

这个该死的 \(DFS\) 我愣是搞了好几天.

然后今天上午地理学考模拟考试的时候,

由于题太水(nan)了,

一会就水完了,

然后就想到了这个题,

我就花了一个图,

发现如果是从编号大的点向编号小的点走,

只能是拆点拆出来的点(想一想为什么),

因为我们如果是从编号大的向编号小的走,

且这两个点不是一个城市的话,

那么我们一定是从东向西走,

而按照我们的思路来,

则是应该从东往西走两趟,

所以我们走的这条边一定是我们没走的(尽管它的流量已经达到了容量),

于是乎就过啦!

\(code:\)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <map>
using namespace std;
const int maxn = 2e2 + 5, maxm = 2e4 + 4;
int n, m, s, t, flow[maxn], d[maxn], pre[maxn], num[maxn];
int tot = 1, to[maxm], cap[maxm], cost[maxm], nxt[maxm], head[maxn];
string name[maxn];
int maxcost, maxflow;
bool vis[maxn], use[maxn];
queue <int> q;
map <string, int> mp;
int read(){
    int x = 0;
    char ch = getchar();
    while (ch < '0' || ch > '9') ch = getchar();
    while (ch >= '0' && ch <= '9'){
        x = (x << 3) + (x << 1) + (ch ^ 48);
        ch = getchar();
    }
    return x;
}
void add(int u, int v, int w, int c){
    to[++tot] = v, cap[tot] = w, cost[tot] = c, nxt[tot] = head[u], head[u] = tot;
    to[++tot] = u, cap[tot] = 0, cost[tot] = -c, nxt[tot] = head[v], head[v] = tot;
}
bool SPFA(){
    memset(d, -1, sizeof(d));
    memset(flow, 0x3f, sizeof(flow));
    memset(vis, 0, sizeof(vis));
    q.push(s);
    d[s] = 0; pre[t] = -1;
    while (q.size()){
        int x = q.front(); q.pop();
        vis[x] = 0;
        for (int i = head[x]; i; i = nxt[i]){
            int y = to[i], z = cost[i];
            if (d[y] < d[x] + z && cap[i]){
                d[y] = d[x] + z;
                pre[y] = x;
                num[y] = i;
                flow[y] = min(flow[x], cap[i]);
                if (vis[y] == 0){
                    q.push(y);
                    vis[y] = 1;
                }
            }
        }
    }
    return pre[t] != -1;
}
void MCMF(){
    while (SPFA()){
        int now = t;
        maxflow += flow[t];
        maxcost += flow[t] * d[t];
        while (now != s){
            cap[num[now]] -= flow[t];
            cap[num[now] ^ 1] += flow[t];
            now = pre[now];
        }
    }
}
void DFS1(int x){
    if (x <= n) cout << name[x] << "\n";
    use[x] = 1;
    for (int i = head[x]; i; i = nxt[i]){
        int y = to[i];
        if (cap[i] == 0 && !(y > x && y - x != n)){
          use[y] = 1;
          DFS1(y);
          break;
        }
    }
}
void DFS2(int x){
    for (int i = head[x]; i; i = nxt[i]){
        int y = to[i];
        if (cap[i] == 0 && !(y > x && y - x != n) && use[y] == 0){
          use[y] = 1;
          DFS2(y);
          break;
        }
    }
    if (x <= n) cout << name[x] << "\n";
    use[x] = 1;
}
int main(){
    n = read(), m = read(); s = 1, t = n;
    for (int i = 1; i <= n; i++){
        cin >> name[i];
        mp[name[i]] = i;
    }
    add(1, n + 1, 2, 0);
    for (int i = 2; i < n; i++) add(i, i + n, 1, 1);
    for (int i = 1; i <= m; i++){
        string x, y;
        cin >> x >> y;
        int u = mp[x], v = mp[y];
        if (u > v) swap(u, v);
        u += n;
        add(u, v, 1, 0);
    }
    MCMF();
    if (maxflow == 0){
        printf("No Solution!");
        return 0;
    }
    printf("%d\n", maxcost + 2);
    cout << name[1] << "\n";
    DFS1(1 + n);
    DFS2(1 + n);
    cout << name[1] << "\n";
    return 0;
}

qwq

posted @ 2021-08-22 16:26  sshadows  阅读(40)  评论(0编辑  收藏  举报