• 洛谷 P2756 飞行员配对方案问题 (二分图匹配)


    题目链接:P2756 飞行员配对方案问题

    题意

    给定 (m) 个外籍飞行员和 (n - m) 个英国飞行员,每一架飞机需要一名英国飞行员和一名外籍飞行员,求最多能派出几架飞机。

    思路

    最大流

    二分图最大匹配的模板题。

    建立一个超级源点 (s) 和一个超级汇点 (t)。让 (s) 与所有的外籍飞行员建立有向边,所有的英国飞行员与 (t) 建立有向边。让所有边的容量为 (1),求最大流即可。最后找出所有流量为 (1) 的反向边即可。

    此题也可以使用匈牙利算法。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    const int inf = 0x3f3f3f3f;
    const int N = 500;
    const int M = 1e5 + 10;
    
    int head[N], ver[M], edge[M], Next[M], d[N];
    int tot, maxflow;
    int s, t;
    
    void add(int x, int y, int z) {
        ver[++tot] = y, edge[tot] = z, Next[tot] = head[x], head[x] = tot;
        ver[++tot] = x, edge[tot] = 0, Next[tot] = head[y], head[y] = tot;
    }
    
    bool bfs() {
        memset(d, 0, sizeof(d));
        queue<int> q;
        q.push(s); d[s] = 1;
        while(q.size()) {
            int x = q.front(); q.pop();
            for(int i = head[x]; i; i = Next[i]) {
                if(edge[i] && !d[ver[i]]) {
                    q.push(ver[i]);
                    d[ver[i]] = d[x] + 1;
                    if(ver[i] == t) return 1;
                }
            }
        }
        return 0;
    }
    
    int dinic(int x, int flow) {
        if(x == t) return flow;
        int rest = flow, k;
        for(int i = head[x]; i && rest; i = Next[i]) {
            if(edge[i] && d[ver[i]] == d[x] + 1) {
                k = dinic(ver[i], min(rest, edge[i]));
                if(!k) d[ver[i]] = 0;
                edge[i] -= k;
                edge[i ^ 1] += k;
                rest -= k;
            }
        }
        return flow - rest;
    }
    
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(0);
        int n, m;
        cin >> m >> n;
        tot = 1;
        s = 0;
        t = n + 1;
        for(int i = 1; i <= m; ++i) add(s, i, 1);
        for(int i = m + 1; i <= n; ++i) add(i, t, 1);
        int u, v;
        while(cin >> u >> v) {
            if(u == -1 && v == -1) break;
            add(u, v, 1);
        }
        int flow = 0;
        while(bfs()) {
            while(flow = dinic(s, inf)) {
                maxflow += flow;
            }
        }
        if(maxflow == 0) {
            cout << "No Solution!" << endl;
            return 0;
        }
        cout << maxflow << endl;
        for(int i = 1; i <= m; ++i) {
            for(int j = head[i]; j; j = Next[j]) {
                if(ver[j] != s && edge[j] == 0 && edge[j ^ 1] == 1) {
                    cout << i << " " << ver[j] << endl;
                }
            }
        }
        return 0;
    }
    

    参考

    《算法竞赛进阶指南》 李煜东 著

  • 相关阅读:
    poj 2584 T-Shirt Gumbo (二分匹配)
    hdu 1757 A Simple Math Problem (乘法矩阵)
    矩阵之矩阵乘法(转载)
    poj 2239 Selecting Courses (二分匹配)
    hdu 3661 Assignments (贪心)
    hdu 1348 Wall (凸包)
    poj 2060 Taxi Cab Scheme (二分匹配)
    hdu 2202 最大三角形 (凸包)
    hdu 1577 WisKey的眼神 (数学几何)
    poj 1719 Shooting Contest (二分匹配)
  • 原文地址:https://www.cnblogs.com/wulitaotao/p/11565359.html
Copyright © 2020-2023  润新知