网络流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!’。
输入输出样例
先来一段匈牙利算法AC代码,关于匈牙利算法的说明看其他博客去,这里重点是网络流。。。首先你要有前置技能
1,会求最大流(dinic, isap, EK, FF 随便会一个)。
2,知道什么是二分图匹配
#include <bits/stdc++.h> using namespace std;
const int MAXN = ;
const int INF = 0x3F3F3F3F; int n, m, first[MAXN], sign; struct Edge {
int to, w, next;
} edge[MAXN * MAXN]; int link[MAXN], vis[MAXN]; inline void init() {
for(int i = ; i <= n; i++ ) {
first[i] = -;
}
sign = ;
} inline void add_edge(int u, int v, int w) {
edge[sign].to = v;
edge[sign].w = w;
edge[sign].next = first[u];
first[u] = sign ++;
} bool match(int x) {
for(int i = first[x]; ~i; i = edge[i].next) {
int to = edge[i].to;
if(!vis[to]) {
vis[to] = ;
if(!link[to] || match(link[to])) {
link[to] = x;
return ;
}
}
}
return ;
} int main()
{
while(~scanf("%d %d", &n, &m)) {
init();
int u, v;
while(~scanf("%d %d", &u, &v)) {
if(u == - && v == -) {
break;
}
add_edge(u, v, );
}
memset(link, , sizeof(link));
int ans = ;
for(int i = ; i <= n; i++ ) {
memset(vis, , sizeof(vis));
if(match(i)) {
ans ++;
}
}
if(ans) {
printf("%d\n", ans);
vector<pair<int, int> > vec;
for(int i = n + ; i <= n + m; i++ ) {
if(link[i]) {
vec.push_back(make_pair(link[i], i));
}
}
auto cmp = [](pair<int, int> &a, pair<int, int> &b) {
return a.first < b.first;
};
sort(vec.begin(), vec.end(), cmp);
for(int i = ; i < vec.size(); i++ ) {
printf("%d %d\n", vec[i].first, vec[i].second);
}
} else {
puts("No Solution!");
}
}
return ;
}
网络流的解法。
用网络流写二分图是因为我KM算法了学吐了。。。 然后发现网络流的dinic在二分图中具有着优秀的复杂度。学习一波。对于无权二分图,我们可以让起边权为1,虚拟出源点,源点引出一系列权值1的边指向集合A的所有点。集合B的所有点引出一条权值1的边指向汇点。然后直接dinic最大流即可。然后一个问题就是如何把匹配关系找出来。这部分看注释。另外这题又spacial judge。匹配结果可行集合,不需要与案例一样。
关于匹配点这么获得:
网络流解二分图,正向弧和反向弧权要么是1,要么是0 .而且集合只有两个。没有普通网络流中间的一堆点。集合B中边权是1,且不指向t的点。就是集合A中他的匹配点。(想明白后感觉我又废话了,其他题解都没解释,这部分卡了我十几分钟囧。。。)
#include <bits/stdc++.h> using namespace std;
const int maxn = ;
const int maxm = 1e4 + ;
const int inf = 0x7fffffff;
typedef long long LL; int s, t, n, m; struct Edge {
int to, w, next;
} edge[maxm]; int first[maxn], cur[maxn], sign, dist[maxn]; void init() {
for(int i = ; i <= n + m + ; i ++ ) {
first[i] = -;
}
sign = ;
} void add_edge(int u,int v,int w) {
edge[sign].to = v, edge[sign].w = w;
edge[sign].next = first[u], first[u] = sign++; edge[sign].to = u, edge[sign].w = ;
edge[sign].next = first[v], first[v] = sign++;
} bool bfs(int s,int t) {
memset(dist, -, sizeof(dist));
queue<int>que;
que.push(s), dist[s] = ;
while(!que.empty()) {
int now = que.front();
que.pop();
if(now == t) {
return ;
}
for(int i = first[now]; ~i; i = edge[i].next) {
int to = edge[i].to, ww = edge[i].w;
if(dist[to] == - && ww > ) {
dist[to] = dist[now] + ;
que.push(to);
}
}
}
return ;
} int dfs(int s, int t, int max_flow) {
if(s == t) {
return max_flow;
}
for(int &i = cur[s]; ~i; i = edge[i].next) {
int to = edge[i].to, ww = edge[i].w;
if(dist[to] == dist[s] + && ww > ) {
int flow = dfs(to, t, min(max_flow, ww));
if(flow > ) {
edge[i].w -= flow;
edge[i ^ ].w += flow;
return flow;
}
}
}
return ;
} int dinic(int s, int t) {
int ans = ;
while(bfs(s, t)) {
for(int i = ; i <= t; i ++ ) {
cur[i] = first[i];
}
ans += dfs(s, t, inf);
}
return ans;
} int main() { while(~scanf("%d %d", &n, &m)) {
init();
s = , t = n + m + ;
for(int i = ; i <= n; i++ ) {
add_edge(, i, );
}
for(int i = n + ; i <= n + m; i++ ) {
add_edge(i, t, );
}
int u, v;
while(~scanf("%d %d", &u, &v)) {
if(u == - && v == -) {
break;
}
add_edge(u, v, );
}
int ans = dinic(s, t);
printf("%d\n", ans);
if(ans) {
for(int i = n + ; i <= n + m; i++ ) {
for(int j = first[i]; ~j; j = edge[j].next) {
if(edge[j].w == && edge[j].to != t) {
printf("%d %d\n", edge[j].to, i);
}
}
} } else {
puts("No Solution!");
}
}
return ;
}
一个封装的Dinic
#include <bits/stdc++.h>
using namespace std;
struct Dinic {
static const int MAXN = 1e4 + ;
static const int MAXM = 1e5 + ;
static const int INF = 0x3f3f3f3f;
int n, m, s, t;
int first[MAXN], cur[MAXN], dist[MAXN], sign;
struct Node {
int to, flow, next;
} edge[MAXM * ];
inline void init(int start, int vertex, int ss, int tt) {
n = vertex, s = ss, t = tt;
for(int i = start; i <= n; i++ ) {
first[i] = -;
}
sign = ;
}
inline void addEdge(int u, int v, int flow) {
edge[sign].to = v, edge[sign].flow = flow, edge[sign].next = first[u];
first[u] = sign++;
}
inline void add_edge(int u, int v, int flow) {
addEdge(u, v, flow);
addEdge(v, u, );
}
inline int dinic() {
int max_flow = ;
while(bfs(s, t)) {
for(int i = ; i <= n; i++ ) {
cur[i] = first[i];
}
max_flow += dfs(s, INF);
}
return max_flow;
}
bool bfs(int s, int t) {
memset(dist, -, sizeof(dist));
queue<int>que;
que.push(s), dist[s] = ;
while(!que.empty()) {
int now = que.front();
que.pop();
if(now == t) {
return ;
}
for(int i = first[now]; ~i; i = edge[i].next) {
int to = edge[i].to, flow = edge[i].flow;
if(dist[to] == - && flow > ) {
dist[to] = dist[now] + ;
que.push(to);
}
}
}
return ;
}
int dfs(int now, int max_flow) {
if(now == t) {
return max_flow;
}
for(int &i = cur[now]; ~i; i = edge[i].next) {
int to = edge[i].to, flow = edge[i].flow;
if(dist[to] == dist[now] + && flow > ) {
int next_flow = dfs(to, min(flow, max_flow));
if(next_flow > ) {
edge[i].flow -= next_flow;
edge[i ^ ].flow += next_flow;
return next_flow;
}
}
}
return ;
}
///显示二分图匹配结果,n,m分别是两个集合的大小
void show(int n, int m) {
for(int i = n + ; i <= n + m; i++ ) {
for(int j = first[i]; ~j; j = edge[j].next) {
if(edge[j].flow == && edge[j].to != t) {
printf("%d %d\n", edge[j].to, i);
}
}
}
}
} cwl;
int main() {
int n, m;
int u, v;
scanf("%d %d", &n, &m);
cwl.init(, n + m + , , n + m + );
for(int i = ; i <= n; i++ ) {
cwl.add_edge(, i, );
}
for(int i = n + ; i <= n + m; i++ ) {
cwl.add_edge(i, n + m + , );
}
while(~scanf("%d %d", &u, &v)) {
if(u == - && v == -) {
break;
}
cwl.add_edge(u, v, );
}
int ans = cwl.dinic();
printf("%d\n", ans);
if(ans) {
cwl.show(n, m);
} else {
puts("No Solution!");
}
return ;
}
网络流24题第一题(luogu2796飞行员配对方案)的更多相关文章
- [网络流 24 题] luoguP2756 飞行员配对方案问题
[返回网络流 24 题索引] 题目描述 英国皇家空军从沦陷国征募了大量外籍飞行员.由皇家空军派出的每一架飞机都需要配备在航行技能和语言上能互相配合的 222 名飞行员,其中 111 名是英国飞行员,另 ...
- P2756 飞行员配对方案问题(网络流24题之一)
题目背景 第二次世界大战时期.. 题目描述 英国皇家空军从沦陷国征募了大量外籍飞行员.由皇家空军派出的每一架飞机都需要配备在航行技能和语言上能互相配合的2 名飞行员,其中1 名是英国飞行员,另1名是外 ...
- 网络二十四题 之 P2756 飞行员配对方案问题
题目背景 第二次世界大战时期.. 题目描述 英国皇家空军从沦陷国征募了大量外籍飞行员.由皇家空军派出的每一架飞机都需要配备在航行技能和语言上能互相配合的2 名飞行员,其中1 名是英国飞行员,另1名是外 ...
- 洛谷 P2756 飞行员配对方案问题 (二分图/网络流,最佳匹配方案)
P2756 飞行员配对方案问题 题目背景 第二次世界大战时期.. 题目描述 英国皇家空军从沦陷国征募了大量外籍飞行员.由皇家空军派出的每一架飞机都需要配备在航行技能和语言上能互相配合的2 名飞行员,其 ...
- P2756 飞行员配对方案问题 网络流
P2756 飞行员配对方案问题 #include <bits/stdc++.h> using namespace std; , inf = 0x3f3f3f; struct Edge { ...
- 洛谷P2756飞行员配对方案问题 P2055假期的宿舍【二分图匹配】题解+代码
洛谷 P2756飞行员配对方案问题 P2055假期的宿舍[二分图匹配] 飞行员配对方案问题 题目背景 第二次世界大战时期.. 题目描述 英国皇家空军从沦陷国征募了大量外籍飞行员.由皇家空军派出的每一架 ...
- 【CJOJ1494】【洛谷2756】飞行员配对方案问题
题面 题目背景 第二次世界大战时期.. 题目描述 英国皇家空军从沦陷国征募了大量外籍飞行员.由皇家空军派出的每一架飞机都需要配备在航行技能和语言上能互相配合的2 名飞行员,其中1 名是英国飞行员,另1 ...
- AC日记——飞行员配对方案问题 洛谷 P2756
题目背景 第二次世界大战时期.. 题目描述 英国皇家空军从沦陷国征募了大量外籍飞行员.由皇家空军派出的每一架飞机都需要配备在航行技能和语言上能互相配合的2 名飞行员,其中1 名是英国飞行员,另1名是外 ...
- Luogu 2756 飞行员配对方案问题(二分图最大匹配)
Luogu 2756 飞行员配对方案问题(二分图最大匹配) Description 英国皇家空军从沦陷国征募了大量外籍飞行员.由皇家空军派出的每一架飞机都需要配备在航行技能和语言上能互相配合的2 名飞 ...
随机推荐
- python基础——内置函数
python基础--内置函数 一.内置函数(python3.x) 内置参数详解官方文档: https://docs.python.org/3/library/functions.html?highl ...
- POJ-1068 Parencodings---模拟括号的配对
题目链接: https://vjudge.net/problem/POJ-1068 题目大意: 给出一种括号序列的表示形式名叫P序列,规则是统计出每个右括号之前的左括号个数作为序列每项的值.然后要求你 ...
- 学习linux的一些指令
简单说一下我对linux的理解,linux只有一个根目录,所有目录都挂在该根目录上,磁盘进行分区,然后生成文件系统,挂到目录上,/etc/fstab用于记录系统配置,比如分区挂载点,开机自动挂载等等. ...
- laravel5.5 使用alipay SDK报错Cannot redeclare Encrypt() (previously declared in ../vendor/laravel/framework/src/Illuminate/Foundation/helpers.php:448)
错误现象: 在laravel5.5 中,使用alipaySDK 报错: Cannot redeclare Encrypt() (previously declared in ../vendor/lar ...
- jq跨域获取json
<!DOCTYPE html><html lang="zh"> <head> <meta charset="UTF-8" ...
- 将python代码打印成pdf
将python代码打印成pdf,打印出来很丑,完全不能看. mac下:pycharm 编辑器有print的功能,但是会提示: Error: No print service found. 所以需要一个 ...
- [WC 2014]紫荆花之恋
Description 强强和萌萌是一对好朋友.有一天他们在外面闲逛,突然看到前方有一棵紫荆树.这已经是紫荆花飞舞的季节了,无数的花瓣以肉眼可见的速度从紫荆树上长了出来. 仔细看看的话,这个大树实际上 ...
- [HNOI 2015]接水果
Description 风见幽香非常喜欢玩一个叫做 osu!的游戏,其中她最喜欢玩的模式就是接水果. 由于她已经DT FC 了The big black, 她觉得这个游戏太简单了,于是发明了一个更 ...
- [ZJOI 2006]物流运输
Description 物流公司要把一批货物从码头A运到码头B.由于货物量比较大,需要n天才能运完.货物运输过程中一般要转停好几个码头.物流公司通常会设计一条固定的运输路线,以便对整个运输过程实施严格 ...
- [SDOI2010]古代猪文
题目背景 “在那山的那边海的那边有一群小肥猪.他们活泼又聪明,他们调皮又灵敏.他们自由自在生活在那绿色的大草坪,他们善良勇敢相互都关心……” ——选自猪王国民歌 很久很久以前,在山的那边海的那边的某片 ...