【网络流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\n", ans);
    for (int i = m + 1; i <= n; i++)
        if (match[i]) {
            printf("%d %d\n", 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\n", 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\n", i, to);
                break;
            }
        }
    }
    return 0;
}
posted @ 2020-09-02 23:45  icysky  阅读(187)  评论(0编辑  收藏  举报