前置知识
题意
题目描述
英国皇家空军从沦陷国征募了大量外籍飞行员。由皇家空军派出的每一架飞机都需要配备在航行技能和语言上能互相配合的2 名飞行员,其中1 名是英国飞行员,另1名是外籍飞行员。在众多的飞行员中,每一名外籍飞行员都可以与其他若干名英国飞行员很好地配合。如何选择配对飞行的飞行员才能使一次派出最多的飞机。对于给定的外籍飞行员与英国飞行员的配合情况,试设计一个算法找出最佳飞行员配对方案,使皇家空军一次能派出最多的飞机。
对于给定的外籍飞行员与英国飞行员的配合情况,编程找出一个最佳飞行员配对方案,使皇家空军一次能派出最多的飞机。
输入输出格式
输入格式:
第 1 行有 2 个正整数 m m m 和 n n n。 n n n 是皇家空军的飞行员总数 ( n < 100 ) (n<100) (n<100); m m m 是外籍飞行员数 ( m < = n ) (m<=n) (m<=n)。外籍飞行员编号为 1 − m 1-m 1−m;英国飞行员编号为 ( m + 1 ) − n (m+1)-n (m+1)−n。
接下来每行有 2 个正整数 i i i 和 j j j,表示外籍飞行员 i i i 可以和英国飞行员 j j j 配合。最后以 2个 − 1 -1 −1 结束。
输出格式:
第 1 行是最佳飞行员配对方案一次能派出的最多的飞机数 M。接下来 M 行是最佳飞行员配对方案。每行有 2个正整数 i i i和 j j j,表示在最佳飞行员配对方案中,飞行员 i i i和飞行员 j j j 配对。如果所求的最佳飞行员配对方案不存在,则输出‘No Solution!’。
总体思路
S向英国飞行员连边,外国飞行员向T连边,可以配对的2人之间连边,跑网络流,最后扫描整张图,选出正向边为0的边或反向边为1的边,判断S和T是否为其两端,若不是,则输出。
代码
#include<bits/stdc++.h>
using namespace std;
int n,m,s,t;
int first[100005],nxt[100005],to[100005],w[100005],dep[100005],cnt[100005],tot=1,US[100005],vis[100005];
struct solu{
int x,y;
}S[50005];
int Cnt=0;
int Read(){
int x=0,f=1;
char ch=getchar();
while(!isdigit(ch)){
if(ch=='-') f=-1;
ch=getchar();
}
while(isdigit(ch)){
x=(x<<3)+(x<<1)+ch-'0';
ch=getchar();
}
return x*f;
}
void Add(int x,int y,int z){
nxt[++tot]=first[x];
first[x]=tot;
to[tot]=y;
w[tot]=z;
}
void Bfs(int s){
memset(dep,0xff,sizeof(dep));
dep[s]=0;
cnt[0]=1;
queue<int> q;
q.push(s);
while(!q.empty()){
int u=q.front();
q.pop();
for(int e=first[u];e;e=nxt[e]){
int v=to[e];
if(dep[v]==-1){
++cnt[dep[v]=dep[u]+1];
q.push(v);
}
}
}
}
int mf=0,ind=0;
int dfs(int p,int f){
if(p==t){
mf+=f;
return f;
}
int u=0;
for(int e=first[p];e;e=nxt[e]){
if(w[e]&&dep[to[e]]==dep[p]-1){
int uu=dfs(to[e],min(w[e],f-u));
if(uu){
S[++Cnt].x=p;
S[Cnt].y=to[e];
w[e]-=uu;
w[e^1]+=uu;
u+=uu;
}
if(u==f) return u;
}
}
if(!--cnt[dep[p]]){
dep[s]=n+1;
}
++cnt[++dep[p]];
return u;
}
void bfs2(){
queue<int> q;
q.push(s);
vis[s]=true;
while(!q.empty()){
int u=q.front();
q.pop();
for(int e=first[u];e;e=nxt[e]){
q.push(to[e]);
if(w[e]==0&&!vis[to[e]]){
vis[to[e]]=true;
if(u==0||to[e]==0) continue; //若与S联通则返回
if(u==n+1||to[e]==n+1) continue; //与T联通同理
cout<<u<<" "<<to[e]<<endl; //输出答案
ind++;
if(ind==mf) return ; //若已经输出完毕则结束
}
}
}
}
signed main(){
memset(US,false,sizeof(US));
memset(vis,false,sizeof(vis));
m=Read(),n=Read();
s=0,t=n+1;
for(int i=1;i<=m;i++){
Add(s,i,1);
Add(i,s,0);
}
for(int i=m+1;i<=n;i++){
Add(i,t,1);
Add(t,i,0);
}
while(1){
int p=Read(),q=Read();
if(p==-1&&q==-1) break;
Add(p,q,1);
Add(q,p,0);
}
Bfs(t);
while(dep[s]<n){
dfs(s,0x3ffffff);
}
if(mf==0){
cout<<"No Solution!"<<endl;
return 0;
}
cout<<mf<<endl;
bfs2();//输出答案
return 0;
}
本文介绍了一个基于网络流算法解决飞行员配对问题的方法。通过构造特定的网络流模型,实现英国皇家空军中外籍与英国飞行员之间的最优配对,使得能够同时派出最多数量的飞机。

604

被折叠的 条评论
为什么被折叠?



