网络流24题第一题(luogu2796飞行员配对方案)

飞行员配对方案

二分图裸题,可以拿最大流怼。

题目背景

第二次世界大战时期..

题目描述

英国皇家空军从沦陷国征募了大量外籍飞行员。由皇家空军派出的每一架飞机都需要配备在航行技能和语言上能互相配合的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 

先来一段匈牙利算法AC代码,关于匈牙利算法的说明看其他博客去,这里重点是网络流。。。首先你要有前置技能

  1,会求最大流(dinic, isap, EK, FF 随便会一个)。

  2,知道什么是二分图匹配

 1 #include <bits/stdc++.h>
 2
 3 using namespace std;
 4 const int MAXN = 205;
 5 const int INF = 0x3F3F3F3F;
 6
 7 int n, m, first[MAXN], sign;
 8
 9 struct Edge {
10     int to, w, next;
11 } edge[MAXN * MAXN];
12
13 int link[MAXN], vis[MAXN];
14
15 inline void init() {
16     for(int i = 0; i <= n; i++ ) {
17         first[i] = -1;
18     }
19     sign = 0;
20 }
21
22 inline void add_edge(int u, int v, int w) {
23     edge[sign].to = v;
24     edge[sign].w = w;
25     edge[sign].next = first[u];
26     first[u] = sign ++;
27 }
28
29 bool match(int x) {
30     for(int i = first[x]; ~i; i = edge[i].next) {
31         int to = edge[i].to;
32         if(!vis[to]) {
33             vis[to] = 1;
34             if(!link[to] || match(link[to])) {
35                 link[to] = x;
36                 return 1;
37             }
38         }
39     }
40     return 0;
41 }
42
43 int main()
44 {
45     while(~scanf("%d %d", &n, &m)) {
46         init();
47         int u, v;
48         while(~scanf("%d %d", &u, &v)) {
49             if(u == -1 && v == -1) {
50                 break;
51             }
52             add_edge(u, v, 1);
53         }
54         memset(link, 0, sizeof(link));
55         int ans = 0;
56         for(int i = 1; i <= n; i++ ) {
57             memset(vis, 0, sizeof(vis));
58             if(match(i)) {
59                 ans ++;
60             }
61         }
62         if(ans) {
63             printf("%d\n", ans);
64             vector<pair<int, int> > vec;
65             for(int i = n + 1; i <= n + m; i++ ) {
66                 if(link[i]) {
67                     vec.push_back(make_pair(link[i], i));
68                 }
69             }
70             auto cmp = [](pair<int, int> &a, pair<int, int> &b) {
71                 return a.first < b.first;
72             };
73             sort(vec.begin(), vec.end(), cmp);
74             for(int i = 0; i < vec.size(); i++ ) {
75                 printf("%d %d\n", vec[i].first, vec[i].second);
76             }
77         } else {
78             puts("No Solution!");
79         }
80     }
81     return 0;
82 }

网络流的解法。

  用网络流写二分图是因为我KM算法了学吐了。。。 然后发现网络流的dinic在二分图中具有着优秀的复杂度。学习一波。对于无权二分图,我们可以让起边权为1,虚拟出源点,源点引出一系列权值1的边指向集合A的所有点。集合B的所有点引出一条权值1的边指向汇点。然后直接dinic最大流即可。然后一个问题就是如何把匹配关系找出来。这部分看注释。另外这题又spacial judge。匹配结果可行集合,不需要与案例一样。

关于匹配点这么获得:

网络流解二分图,正向弧和反向弧权要么是1,要么是0 .而且集合只有两个。没有普通网络流中间的一堆点。集合B中边权是1,且不指向t的点。就是集合A中他的匹配点。(想明白后感觉我又废话了,其他题解都没解释,这部分卡了我十几分钟囧。。。)

  1 #include <bits/stdc++.h>
  2
  3 using namespace std;
  4 const int maxn = 205;
  5 const int maxm = 1e4 + 7;
  6 const int inf  = 0x7fffffff;
  7 typedef long long LL;
  8
  9 int s, t, n, m;
 10
 11 struct Edge {
 12     int to, w, next;
 13 } edge[maxm];
 14
 15 int first[maxn], cur[maxn], sign, dist[maxn];
 16
 17 void init() {
 18     for(int i = 0; i <= n + m + 1; i ++ ) {
 19         first[i] = -1;
 20     }
 21     sign = 0;
 22 }
 23
 24 void add_edge(int u,int v,int w) {
 25     edge[sign].to = v, edge[sign].w = w;
 26     edge[sign].next = first[u], first[u] = sign++;
 27
 28     edge[sign].to = u, edge[sign].w = 0;
 29     edge[sign].next = first[v], first[v] = sign++;
 30 }
 31
 32 bool bfs(int s,int t) {
 33     memset(dist, -1, sizeof(dist));
 34     queue<int>que;
 35     que.push(s), dist[s] = 0;
 36     while(!que.empty()) {
 37         int now = que.front();
 38         que.pop();
 39         if(now == t) {
 40             return 1;
 41         }
 42         for(int i = first[now]; ~i; i = edge[i].next) {
 43             int to = edge[i].to, ww = edge[i].w;
 44             if(dist[to] == -1 && ww > 0) {
 45                 dist[to] = dist[now] + 1;
 46                 que.push(to);
 47             }
 48         }
 49     }
 50     return 0;
 51 }
 52
 53 int dfs(int s, int t, int max_flow) {
 54     if(s == t) {
 55         return max_flow;
 56     }
 57     for(int &i = cur[s]; ~i; i = edge[i].next) {
 58         int to = edge[i].to, ww = edge[i].w;
 59         if(dist[to] == dist[s] + 1 && ww > 0) {
 60             int flow = dfs(to, t, min(max_flow, ww));
 61             if(flow > 0) {
 62                 edge[i].w -= flow;
 63                 edge[i ^ 1].w += flow;
 64                 return flow;
 65             }
 66         }
 67     }
 68     return 0;
 69 }
 70
 71 int dinic(int s, int t) {
 72     int ans = 0;
 73     while(bfs(s, t)) {
 74         for(int i = 0; i <= t; i ++ ) {
 75             cur[i] = first[i];
 76         }
 77         ans += dfs(s, t, inf);
 78     }
 79     return ans;
 80 }
 81
 82 int main() {
 83
 84     while(~scanf("%d %d", &n, &m)) {
 85         init();
 86         s = 0, t = n + m + 1;
 87         for(int i = 1; i <= n; i++ ) {
 88             add_edge(0, i, 1);
 89         }
 90         for(int i = n + 1; i <= n + m; i++ ) {
 91             add_edge(i, t, 1);
 92         }
 93         int u, v;
 94         while(~scanf("%d %d", &u, &v)) {
 95             if(u == -1 && v == -1) {
 96                 break;
 97             }
 98             add_edge(u, v, 1);
 99         }
100         int ans = dinic(s, t);
101         printf("%d\n", ans);
102         if(ans) {
103             for(int i = n + 1; i <= n + m; i++ ) {
104                 for(int j = first[i]; ~j; j = edge[j].next) {
105                     if(edge[j].w == 1 && edge[j].to != t) {
106                         printf("%d %d\n", edge[j].to, i);
107                     }
108                 }
109             }
110
111         } else {
112             puts("No Solution!");
113         }
114     }
115     return 0;
116 }

原文地址:https://www.cnblogs.com/Q1143316492/p/8971979.html

时间: 2024-08-29 06:25:58

网络流24题第一题(luogu2796飞行员配对方案)的相关文章

网络流24题 第一题 - 洛谷2756 飞行员配对方案 二分图匹配 匈牙利算法

欢迎访问~原文出处--博客园-zhouzhendong 去博客园看该题解 题目传送门 题意概括 裸的二分图匹配 题解 匈牙利算法 上板子 代码 #include <cstring> #include <cstdio> #include <algorithm> #include <cstdlib> #include <cmath> using namespace std; const int N=100+5; int m,n,a,b,match[N

网络流24题 洛谷 2756 飞行员配对方案

代码风格迥异 -- 1 #include<bits/stdc++.h> 2 3 const int N=1000+5; 4 5 using namespace std; 6 7 int link[N],g[N][N],ansx[N]; 8 int n,m,u,v,ans; 9 bool vis[N]; 10 11 inline void read( int&x ) { 12 int f=1;x=0;char c=getchar(); 13 while(c>'9'||c<'0

「网络流24题」1. 飞行员配对方案问题

「网络流24题」1. 飞行员配对方案问题 <题目链接> 比较经典的一道二分图最大匹配. 匈牙利算法走起啊. 算出答案后,输出每个外籍飞行员匹配的点(如果有)即可. 匈牙利算法,简而言之就是,每个x部点u去找自己能匹配上的第一个y部点v,如果v还没有被匹配,或是v已经匹配的x部点w还能匹配其他y部点)就将x与y匹配. 「如果我除了她(v)还能追到别的妹子,我就把她让给你.」--w对x如是说. 代码简明易懂. #include <cstdio> #include <cstring

【网络流24题】飞行员配对方案问题

[网络流24题]飞行员配对方案问题 题面 这些题都用Cogs交算了 因为cogs有SPJ 题面 题解 很简单的二分图匹配 匈牙利算法就能够解决 求最大流的话 再加上一个源点一个汇点即可 #include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<algorithm> #include<set>

dinic求解二分图最大匹配&amp;&amp;网络流24题之飞行员配对方案问题

在二分图的基础上增加源S和汇T.1.S向X集合中每个顶点连一条容量为1的有向边.2.Y集合中每个顶点向T连一条容量为1的有向边.3.XY集合之间的边都设为从A集合中的点到B集合之中的点,容量为1的有向边. 求网络最大流,流量就是匹配数,所有满流边是一组可行解. 所以就解决了. 飞行员配对方案问题: 题目背景 第二次世界大战时期.. 题目描述 英国皇家空军从沦陷国征募了大量外籍飞行员.由皇家空军派出的每一架飞机都需要配备在航行技能和语言上能互相配合的2 名飞行员,其中1 名是英国飞行员,另1名是外

【 网络流24 】飞行员配对方案问题

第二次世界大战时期,英国皇家空军从沦陷国征募了大量外籍飞行员.由皇家空军派出的每一架飞机都需要配备在航行技能和语言上能互相配合的 2 名飞行员,其中 1 名是英国飞行员,另 1 名是外籍飞行员.在众多的飞行员中,每一名外籍飞行员都可以与其他若干名英国飞行员很好地配合.如何选择配对飞行的飞行员才能使一次派出最多的飞机.对于给定的外籍飞行员与英国飞行员的配合情况,试设计一个算法找出最佳飞行员配对方案,使皇家空军一次能派出最多的飞机. 对于给定的外籍飞行员与英国飞行员的配合情况,编程找出一个最佳飞行员

飞行员配对方案问题 2011-12-29

算法实现题8-1 飞行员配对方案问题(习题 8-10) ´问题描述: 第二次世界大战时期, 英国皇家空军从沦陷国征募了大量外籍飞行员.由皇家空军派出的每一架飞机都需要配备在航行技能和语言上能互相配合的2 名飞行员, 其中1 名是英国飞行员,另1名是外籍飞行员.在众多的飞行员中,每一名外籍飞行员都可以与其他若干名英国飞行员很好地配合. 如何选择配对飞行的飞行员才能使一次派出最多的飞机.对于给定的外籍飞行员与英国飞行员的配合情况,试设计一个算法找出最佳飞行员配对方案,使皇家空军一次能派出最多的飞机.

【二分图匹配/匈牙利算法】飞行员配对方案问题

P2756 飞行员配对方案问题 确认过眼神, 是二分图匹配板子题啦!!! 跑个匈牙利, 有匹配的输出, 记得先输出外籍飞行员, 因为有spj顺序无所谓啦qwq 最近A的最顺利的题了哈哈哈哈哈哈开心!!!!!!!! 1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 using namespace std; 5 const int sz = 100010; 6 int n, m, num = 0, a

[FZYZOJ 1354] 8-1 飞行员配对方案问题

P1354 -- 8-1 飞行员配对方案问题 时间限制:1000MS      内存限制:131072KB      通过/提交人数:38/90 状态:Accepted      标签:    图论-网络流   图论-二分图   无 Description 第二次世界大战时期,英国皇家空军从沦陷国征募了大量外籍飞行员.由皇家空军派出的每一架飞机都需要配备在航行技能和语言上能互相配合的2 名飞行员,其中1 名是英国飞行员,另1 名是外籍飞行员.在众多的飞行员中,每一名外籍飞行员都可以与其他若干名英