网络二十四题 之 P2756 飞行员配对方案问题
题目背景
第二次世界大战时期..
题目描述
英国皇家空军从沦陷国征募了大量外籍飞行员。由皇家空军派出的每一架飞机都需要配备在航行技能和语言上能互相配合的2 名飞行员,其中1 名是英国飞行员,另1名是外籍飞行员。在众多的飞行员中,每一名外籍飞行员都可以与其他若干名英国飞行员很好地配合。如何选择配对飞行的飞行员才能使一次派出最多的飞机。对于给定的外籍飞行员与英国飞行员的配合情况,试设计一个算法找出最佳飞行员配对方案,使皇家空军一次能派出最多的飞机。
对于给定的外籍飞行员与英国飞行员的配合情况,编程找出一个最佳飞行员配对方案,使皇家空军一次能派出最多的飞机。
输入输出格式
输入格式:
第 1 行有 2 个正整数 m 和 n。n 是皇家空军的飞行员总数(n<100);m 是外籍飞行员数(m<=n)。外籍飞行员编号为 1~m;英国飞行员编号为 m+1~n。
接下来每行有 2 个正整数 i 和 j,表示外籍飞行员 i 可以和英国飞行员 j 配合。最后以 2个-1 结束。
输出格式:
第 1 行是最佳飞行员配对方案一次能派出的最多的飞机数 M。接下来 M 行是最佳飞行员配对方案。每行有 2个正整数 i 和 j,表示在最佳飞行员配对方案中,飞行员 i 和飞行员 j 配对。如果所求的最佳飞行员配对方案不存在,则输出‘No Solution!’。
输入输出样例
输入样例#1: 复制
5 10 1 7 1 8 2 6 2 9 2 10 3 7 3 8 4 7 4 8 5 10 -1 -1
输出样例#1: 复制
4 1 7 2 9 3 8 5 10
这个是一个二分图匹配,可以转化成网络流的最大流来写,也可以用二分图的方法来写。
然后我开始就很自然得到选择了最大流的方法来写。
#include <cstdio> #include <vector> #include <cstring> #include <iostream> #include <cstdlib> #include <queue> #include <algorithm> #define inf 0x3f3f3f3f using namespace std; const int maxn = 1010; struct node { int from, to, cap, flow; node(int from=0,int to=0,int cap=0,int flow=0):from(from),to(to),cap(cap),flow(flow){} }; vector<node>e; vector<int>G[maxn]; int level[maxn], iter[maxn]; void init(int n) { for (int i = 0; i <= n; i++) G[i].clear(); e.clear(); } void add(int u,int v,int w) { e.push_back(node(u, v, w, 0)); e.push_back(node(v, u, 0, 0)); int m = e.size(); G[u].push_back(m - 2); G[v].push_back(m - 1); } void bfs(int s) { memset(level, -1, sizeof(level)); level[s] = 0; queue<int>que; que.push(s); while(!que.empty()) { int u = que.front(); que.pop(); for(int i=0;i<G[u].size();i++) { node &now = e[G[u][i]]; if(level[now.to]<0&&now.cap>now.flow) { level[now.to] = level[u] + 1; que.push(now.to); } } } } int dfs(int u,int v,int f) { if (u == v) return f; for(int &i=iter[u];i<G[u].size();i++) { node &now = e[G[u][i]]; if(level[now.to]>level[u]&&now.cap>now.flow) { int d = dfs(now.to, v, min(f, now.cap - now.flow)); if(d>0) { now.flow += d; e[G[u][i] ^ 1].flow -= d; return d; } } } return 0; } int Maxflow(int s,int t) { int flow = 0; while(1) { bfs(s); if (level[t] < 0) return flow; memset(iter, 0, sizeof(iter)); int f; while ((f = dfs(s, t, inf)) > 0) flow += f; } } int main() { int n, m; while(cin>>m>>n) { init(n+2); int s = 0, t = n + 1; for (int i = 1; i <= m; i++) add(s, i, 1); int x, y; while(cin>>x>>y) { if (x == -1 && y == -1) break; add(x, y, 1); } for (int i = m + 1; i <= n; i++) add(i, t, 1); int ans = Maxflow(s,t); cout << ans << endl; if(ans==0) { printf("No Solution!\n"); continue; } for(int i=m+1;i<=n;i++) { for(int j=0;j<G[i].size();j++) { if(e[G[i][j]].to!=t&&e[G[i][j]].flow==-1) { printf("%d %d\n", e[G[i][j]].to, i); } } } } return 0; }
//二分图匹配
#include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> #include <iostream> #include <queue> #include <vector> #define inf 0x3f3f3f3f using namespace std; const int maxn = 1e3; vector<int>G[maxn];//图的邻接表 int match[maxn]; bool used[maxn]; void add(int u,int v) { G[u].push_back(v); G[v].push_back(u); } bool dfs(int v) { used[v] = 1; for(int i=0;i<G[v].size();i++) { int u = G[v][i], w = match[u]; if(w<0||!used[w]&&dfs(w)) { match[v] = u; match[u] = v; return true; } } return false; } int b_m(int n) { int res = 0; memset(match, -1, sizeof(match)); for(int i=1;i<=n;i++) { if(match[i]<0) { memset(used, 0, sizeof(used)); if (dfs(i)) res++; } } return res; } int main() { int m, n; cin >> m >> n; int x, y; while(cin>>x>>y) { if (x == -1 && y == -1) break; add(x, y); } int res = b_m(n); printf("%d\n", res); if (res == 0) printf("No Solution!\n"); else { memset(used, 0, sizeof(used)); for(int i=1;i<=n;i++) { if(match[i]>0&&used[i]==0) { printf("%d %d\n", i, match[i]); used[i] = 1; used[match[i]] = 1; } } } return 0; }