题解 P2756 【飞行员配对方案问题】
千年知乎_天才
2019-09-26 18:06:13
题目名称:飞行员配对方案问题
来源:网络流24题
# 链接
## 博客链接
- [博客园](https://www.cnblogs.com/Alvin-Tree/p/11593308.html)
- [CSDN](https://blog.csdn.net/weixin_43890363/article/details/101448496)
- [洛谷博客](https://www.luogu.org/blog/131abc155-7341-6424/solution-p2756)
- [洛谷题解](https://www.luogu.org/problemnew/solution/P2756)
## 题目链接
- LibreOJ(6000) [题目](https://loj.ac/problem/6000) [提交](https://loj.ac/problem/6000#submit_code) [状态](https://loj.ac/submissions?problem_id=6000) [讨论](https://loj.ac/discussion/problem/6000)
- 洛谷(P2756) [题目](https://www.luogu.org/problem/P2756) [提交](https://www.luogu.org/problem/P2756#submit) [状态](https://www.luogu.org/record/list?pid=P2756) [讨论](https://www.luogu.org/discuss/lists?forumname=P2756)
# 题目大意
有$n$个英国空军和$m$个外籍空军,一架飞机需要一对互相配合的英国空军和外籍空军配合。给出配合情况,求出最多能发动多少飞机。
# 提示
注意题目来源!
# 题解
这是一道最大流裸题。
从原点开始,向每个外籍飞行员连边,容量为$1$。(因为每个外籍飞行员只能被指派一次)
如果外籍飞行员$i$与英国飞行员$j$配合,那么就从$i$向$j$连边,容量为$1$。(每个外籍飞行员与每个英国飞行员最多配合一次)
从每个英国飞行员向汇点连边,容量为$1$。(一对飞行员相互配合只能发动一架飞机)
拿样例说话,如图所示
![《飞行员配对方案问题》网络图](https://cdn.luogu.com.cn/upload/image_hosting/nlrcjsyc.png)
其中$F$表示外籍飞行员,$E$表示英国飞行员。
然后跑一遍$Dinic$就得到答案了。
```cpp
//C++
#include<bits/locale_facets.h>
#include<stdio.h>
#include<memory.h>
#include<queue>
#define downt(i,n) for(int i=n;i;i=back[i])
#define forto(name,i,d,u) for(name i=d;i<=u;i++)
#define foruntil(name,i,d,u) for(name i=d;i<u;i++)
const int nm=201;
inline void output(long long o);
inline long long input();
template<int nn,int mm,typename name>struct network{
#define nnn (nn+3)
#define mmmm (mm<<2)+2
int s,t,tot,nnnn,last[nnn],level[nnn],to[mmmm],arc[mmmm],back[mmmm];
name c[mmmm];
std::queue<int>q;
network(){nnnn=nnn<<2,INIT();}
#undef nnn
#undef mmmm
void INIT(){tot=1,memset(last,0,nnnn);}
void add(int f,int t,name cap){to[++tot]=t,c[tot]=cap,back[tot]=last[f],last[f]=tot;}
void insert(int f,int t,name cap){
if(cap){
if(cap<0)std::swap(f,t),cap=-cap;
add(f,t,cap),add(t,f,0);
}
}bool climb(){
memset(level,0,nnnn),q.push(s),level[s]=0;
for(int p,too;!q.empty();q.pop()){
p=q.front(),level[p]++;
downt(i,last[p])
if(c[i]&&!level[too=to[i]])level[too]=level[p],q.push(too);
}return level[t];
}name augment(int p,name m){
if(p==t)return m;
name sum=0,flow;
int d=level[p]+1;
for(;arc[p];arc[p]=back[arc[p]])
if(level[to[arc[p]]]==d&&c[arc[p]]){
sum+=(flow=augment(to[arc[p]],std::min(c[arc[p]],(name)(m-sum)))),c[arc[p]]-=flow,c[arc[p]^1]+=flow;
if(sum==m)return m;
}return sum;
}name Dinic(name inf){
name maximum=0;
while(climb()){
foruntil(int,i,s,t)arc[i]=last[i];
maximum+=augment(s,inf);
}return maximum;
}
void new1(short m){
short n=input(),a,b;
s=0,t=n+m+1;
forto(short,i,1,m)insert(0,i,1);
forto(short,i,m+1,m+n)insert(i,t,1);
while(true){
if((a=input())==-1)break;
insert(a,input(),1);
}output(Dinic(100)),putchar('\n');
forto(short,i,1,m)
for(short j=last[i];back[j];j=back[j])
if(!c[j])output(i),putchar(' '),output(to[j]),putchar('\n');
}
};network<200,40000,short>pilot;
int main(){
pilot.new1(input());
return 0;
}inline void output(long long o){
if(o<0)putchar('-'),o=-o;
if(o>=10)output(o/10);
putchar(o%10^'0');
}inline long long input(){
bool minus=false;
char now=getchar();
long long i=0;
for(;!isdigit(now);now=getchar())
if(now=='-')minus=!minus;
for(;isdigit(now);now=getchar())i=(i<<3)+(i<<1)+(now^'0');
return minus?-i:i;
}
```
# 题集
- [网络流24题](https://blog.csdn.net/weixin_43890363/article/details/101509320)
希望这些外籍飞行员里能有中国飞行员。
还是中国飞行员强。