网络流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 名飞 ...
随机推荐
- 新手创建Vue项目
======================安装vue=============================(参考网址:http://www.bubuko.com/infodetail-21320 ...
- 在Visual Studio2017和2015中开发报表项目
1.在sqlserver2008的安装目录中是自带了一个报表开发工具的,但在sqlserver2016中没找到,我推测sqlserver2014也没有,哈,我不探寻这个: 2.在VS2015中想要开发 ...
- Maven 本地仓库明明有jar包,pom文件还是报错解决办法
方法一: 找到出错的jar包文件位置,删掉_maven.repositories文件 方法二: maven中的本地仓库的index索引没有更新导致 解决方案: 在eclipse中打开菜单 window ...
- 点击后退按钮回到本页面中的另一个标签页(tab)
在使用zepto进行微信网页开发的时候,遇到一个情况,在本页面存在四个TAB栏,每点击一个栏会显示相应的内容,下图这种: 现在有一个需求是,用户点击了后退按钮,需要回到上一次点击的tab栏. 这个需求 ...
- 六,前端---viewport
移动设备上的viewport就是设备的屏幕上能用来显示我们的网页的那一块区域,再具体一点,就是浏览器上用来显示网页的那部分区域,但viewport又不局限于浏览器可视区域的大小,它可能比浏览器的可视区 ...
- [LeetCode] Valid Square 验证正方形
Given the coordinates of four points in 2D space, return whether the four points could construct a s ...
- 跨域访问 - 跨域请求 同源策略概念对跨域请求的影响 及几种解决跨域请求的方法如 jsonp
为什么会设置同源策略 > 适用于浏览器的一种资源访问策略 > 同源策略(Same origin policy)是一种约定,它是浏览器最核 心也最 基本的安全功能,如果缺少了同源策略,则浏览 ...
- 51 nod 1681 公共祖先 (主席树+dfs序)
1681 公共祖先 基准时间限制:1 秒 空间限制:131072 KB 分值: 80 难度:5级算法题 有一个庞大的家族,共n人.已知这n个人的祖辈关系正好形成树形结构(即父亲向儿子连边). 在另 ...
- ●BZOJ 3963 [WF2011]MachineWorks
题链: http://www.lydsy.com/JudgeOnline/problem.php?id=3963 题解: 斜率优化DP,CDQ分治. 先按时间排序.(规定以下内容的第i台机器的卖出时间 ...
- 51Nod 1125 交换机器的最小代价
题目描述: 有N台机器重量各不相等,现在要求把这些机器按照重量排序,重量从左到右依次递增.移动机器只能做交换操作,但交换机器要花费一定的费用,费用的大小就是交换机器重量的和.例如:3 2 1,交换1 ...