• 【网络流24题】 1. 飞行员配对问题 题解


    题目链接(洛谷 P2756)

    题意:

    一共有(n)个飞行员,其中有(m)个外籍飞行员和(n - m)个英国飞行员,外籍飞行员从(1)(m)编号英国飞行员从 (m + 1)(n)编号。 对于给定的外籍飞行员与英国飞行员的配合情况,试设计一个算法找出最佳飞行员配对方案,使皇家空军一次能派出最多的飞机。

    思路:

    二分图匹配板题。用匈牙利算法输出匹配会比较方便,而且代码比较短。用网络流的话,给左右两侧的点分别连一条容量为(1)的边,建立一个超级源和超级汇点即可。

    代码:

    匈牙利算法:

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    
    using namespace std;
    const int maxn = 105;
    
    struct Edge {
        int to, nxt;
    }e[maxn * maxn];
    
    int n, m, head[maxn], numedge, match[maxn], vis[maxn], x, y, ans;
    inline void AddEdge(int from, int to) {
        e[numedge].to = to;
        e[numedge].nxt = head[from];
        head[from] = numedge;
        numedge++;
    }
    
    bool dfs(int u, int tag) {
        if (vis[u] == tag) return false;
        vis[u] = tag;
        for (int i = head[u]; ~i; i = e[i].nxt) {
            int to = e[i].to;
            if (!match[to] || dfs(match[to], tag)) {
                match[to] = u;
                return true;
            }
        }
        return false;
    }
    
    int main() {
        memset(head, -1, sizeof(head));
        scanf("%d%d", &m, &n);
        while (scanf("%d%d", &x, &y)) {
            if (x == -1 && y == -1) break;
            AddEdge(x, y);
        }
        for (int i = 1; i <= m; i++) {
            if (dfs(i, i)) ans++;
        }
        printf("%d
    ", ans);
        for (int i = m + 1; i <= n; i++)
            if (match[i]) {
                printf("%d %d
    ", match[i], i);
            }
        return 0;
    }
    

    Dinic算法:

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <queue>
    #define root 0
    #define target 104
    
    using namespace std;
    const int maxn = 105;
    const int INF = 0x3f3f3f3f;
    
    struct Edge {
        int to, val, nxt;
    }e[maxn * maxn * 2];
    int numedge, head[maxn], ans, n, m, x, y, depth[maxn];
    
    inline void AddEdge(int from, int to, int val) {
        e[numedge].to = to;
        e[numedge].val = val;
        e[numedge].nxt = head[from];
        head[from] = numedge;
        numedge++;
    }
    
    bool bfs() {
        memset(depth, 0, sizeof(depth));
        depth[root] = 1;
        queue<int> q;
        q.push(root);
        while (!q.empty()) {
            int u = q.front();
            q.pop();
            for (int i = head[u]; ~i; i = e[i].nxt) {
                int to = e[i].to;
                if (e[i].val > 0 && !depth[to]) {
                    depth[to] = depth[u] + 1;
                    q.push(to);
                }
            }
        }
        return depth[target] != 0;
    }
    
    int dfs(int u, int flow) {
        if (u == target) return flow;
        for (int i = head[u]; ~i; i = e[i].nxt) {
            int to = e[i].to;
            if (e[i].val > 0 && depth[to] > depth[u]) {
                int di = dfs(to, min(flow, e[i].val));
                if (di > 0) {
                    e[i].val -= di;
                    e[i ^ 1].val += di;
                    return di;
                }
            }
        }
        return 0;
    }
    
    inline void Dinic() {
        ans = 0;
        while (bfs()) {
            int d;
            while (d = dfs(root, INF)) {
                ans += d;
            }
        }
    }
    
    int main() {
        memset(head, -1, sizeof(head));
        scanf("%d%d", &m, &n);
        while (scanf("%d%d", &x, &y)) {
            if (x == -1 && y == -1) break;
            AddEdge(x, y, 1);
            AddEdge(y, x, 0);
        }
        for (int i = 1; i <= m; i++) {
            AddEdge(root, i, 1);
            AddEdge(i, root, 0);
        }
        for (int i = m + 1; i <= n; i++) {
            AddEdge(i, target, 1);
            AddEdge(target, i, 0);
        }
        Dinic();
        printf("%d
    ", ans);
        for (int i = 1; i <= m; i++) {
            for (int j = head[i]; ~j; j = e[j].nxt) {
                int to = e[j].to;
                if (to == root) continue;
                if (!e[j].val) {
                    printf("%d %d
    ", i, to);
                    break;
                }
            }
        }
        return 0;
    }
    
  • 相关阅读:
    合并区间
    编程团体赛
    寻找数组的中间位置
    翻转链表2
    链表翻转
    CF1237H. Balanced Reversals
    arc108E
    agc028D
    CF1446D. Frequency Problem
    CF1439D. INOI Final Contests
  • 原文地址:https://www.cnblogs.com/icysky/p/13605159.html
Copyright © 2020-2023  润新知