網絡流24題 P2756 飛行員配對方案問題

題目鏈接

解題思路

問題模型:二分圖最大匹配
轉化模型:網絡最大流

這題我們用網絡流來做。

因爲有多個飛行員,且是有向無環圖,所以我們建立超級源點和超級匯點,這樣才能用網絡流去做。

將超級源點與外籍飛行員11~mm連流量爲11的邊,將英國飛行員m+1m+1n+mn+m與超級匯點連流量爲11的邊,然後將題目給出的邊也連流量爲11的邊即可。

之後再去跑最大流Dinic\text{Dinic}算法,得出最大匹配數,最後輸出時判斷一下就行。

  1. 只判斷正邊,所以從第00條邊開始判斷,每次加22
  2. 判斷當前邊是否與匯點或源點相連,相連則跳過
  3. 判斷邊權是否爲00,爲00則跳過

如果滿足了上述條件,輸出即可,最後給出代碼

代碼

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

const int A = 1e5 + 11;
const int B = 1e6 + 11;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;

inline int read() {
	char c = getchar(); int x = 0, f = 1;
	for ( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
	for ( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
	return x * f;
}

int m, n, cnt, opt, S, T, ans, head[A], d[A], q[A];
struct node { int from, to, nxt, val; } e[A];

inline void add(int from, int to, int val) {
	e[cnt].to = to;
	e[cnt].val = val;
	e[cnt].nxt = head[from];
	head[from] = cnt++;
}

inline bool makelevel(int s, int t) {
	memset(d, 0, sizeof(d));
	memset(q, 0, sizeof(q));
	int l = 0, r = 0;
	d[s] = 1; q[r++] = s;
	while (l < r) {
		int x = q[l++];
		if (x == t) return true;
		for (int i = head[x]; i != -1; i = e[i].nxt) {
			if(d[e[i].to] == 0 && e[i].val) {
				q[r++] = e[i].to;
				d[e[i].to] = d[x] + 1;
			}
		}
	}
	return false;
}

int dfs(int x, int flow, int t) {
	if (x == t) return flow;
	int sum = 0;
	for (int i = head[x]; i != -1; i = e[i].nxt) {
		 if (e[i].val && d[e[i].to] == d[x] + 1) {
		 	int tmp = dfs(e[i].to, min(flow - sum, e[i].val), t);
		 	e[i].val -= tmp, e[i ^ 1].val += tmp;
		 	sum += tmp;
		 	if (sum == flow) return sum;
		 }
	}
	return sum;
}

int main() {
	m = read(), n = read();
	S = 0, T = m + n + 1;
	memset(head, -1, sizeof(head));
	int x, y;
	while (x != -1 && y != -1) {
		add(x, y, 1), add(y, x, 0);
		x = read(), y = read();
	}
	for (int i = 1; i <= m; i++) add(S, i, 1), add(i, S, 0);
	for (int i = m + 1; i <= m + n; i++) add(i, T, 1), add(T, i, 0);
	while (makelevel(S, T)) ans += dfs(S, inf, T);
	cout << ans << '\n';
	for (int i = 0; i <= cnt; i += 2) {
		if (e[i].to != S && e[i ^ 1].to != S)
        	if (e[i].to != T && e[i ^ 1].to != T)
        		if (e[i ^ 1].val != 0) {
            		cout <<  e[i ^ 1].to << " " << e[i].to << '\n';
        		}
	}
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章