网络流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基础数据类型之列表和元组
一.列表 list 列表是python中的基础数据类型之一,其他语言中也有类似于列表的数据类型,比如js中叫数组,他是以[]括起来,每个元素以逗号隔开,而且他里面可以存放各种数据类型比如: li ...
- 1.7 理解dropout
Dropout为什么有正则化的作用? 下面来直观理解一下. 上面讲到,dropout每次迭代都会让一部分神经元失活,这样使得神经网络会比原始的神经网络规模变小,因此采用一个较小神经网络好像和使用正则化 ...
- 一、WINDOWS下 RabbitMQ安装部署
安装需要用管理员权限,全部右键管理员身份运行.建议安装到虚拟机里面,免得影响日常使用. 1.下载 https://dl.bintray.com/rabbitmq/all/rabbitmq-serv ...
- Text-文本撤销
#撤销操作 from tkinter import * master = Tk() #打开undo按钮 text=Text(master,width=30,height=5,undo=True) te ...
- .Net中集合排序还可以这么玩
背景: public class StockQuantity { public StockQuantity(string status, DateTime dateTime, int quantity ...
- 【微信小程序】对微信http请求API的封装,方便对错误码进行处理
/** * App 微信配置文件app.js * author: nujey * versions: 1.0.0 */ App({ /** * @param {Object ...
- ●BOZJ 4456 [Zjoi2016]旅行者
题链: http://www.lydsy.com/JudgeOnline/problem.php?id=4456 题解: 分治好题.大致做法如下:对于一开始的矩形区域,过较长边的中点把矩形区域分为两个 ...
- ●BZOJ 1797 [Ahoi2009]Mincut 最小割
题链: http://www.lydsy.com/JudgeOnline/problem.php?id=1797 题解: 详细的讲解去看http://hzwer.com/3217.html首先跑一个最 ...
- 2015 多校联赛 ——HDU5371(manacher + 枚举)
Sample Input 1 10 2 3 4 4 3 2 2 3 4 4 Sample Output Case #1: 9 要求找出一段数字. 将其分成3部分,第①和第②部分成回文字串,第②和第 ...
- hdu 5441 (并查集)
题意:给你n个点,m条边构成无向图.q个询问,每次一个值,求有多少条路,路中的边权都小于这个值 a->b 和 b->a算两种 思路:把权值从小到大排序,询问从小到大排序,如果相连则用并查集 ...