[网络流24题]飞行员配对方案问题

题目名称:飞行员配对方案问题

来源:网络流24题

链接

博客链接

题目链接

题目内容

题目描述

第二次世界大战时期……英国皇家空军从沦陷国征募了大量外籍飞行员。由皇家空军派出的每一架飞机都需要配备在航行技能和语言上能互相配合的\(2\)名飞行员,其中\(1\)名是英国飞行员,另\(1\)名是外籍飞行员。在众多的飞行员中,每一名外籍飞行员都可以与其他若干名英国飞行员很好地配合。如何选择配对飞行的飞行员才能使一次派出最多的飞机。对于给定的外籍飞行员与英国飞行员的配合情况,试设计一个算法找出最佳飞行员配对方案,使皇家空军一次能派出最多的飞机。

对于给定的外籍飞行员与英国飞行员的配合情况,编程找出一个最佳飞行员配对方案,使皇家空军一次能派出最多的飞机。

题目大意

\(n\)个英国空军和\(m\)个外籍空军,一架飞机需要一对互相配合的英国空军和外籍空军配合。给出配合情况,求出最多能发动多少飞机。

格式

输入

\(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!’。

样例

输入

5 10
1 7
1 8
2 6
2 9
2 10
3 7
3 8
4 7
4 8
5 10
-1 -1

输出

4
1 7
2 9
3 8
5 10 

提示

注意题目来源!

题解

这是一道最大流裸题。

从原点开始,向每个外籍飞行员连边,容量为\(1\)。(因为每个外籍飞行员只能被指派一次)

如果外籍飞行员\(i\)与英国飞行员\(j\)配合,那么就从\(i\)\(j\)连边,容量为\(1\)。(每个外籍飞行员与每个英国飞行员最多配合一次)

从每个英国飞行员向汇点连边,容量为\(1\)。(一对飞行员相互配合只能发动一架飞机)

拿样例说话,如图所示

graph TD s(s)-->|1|F1 s(s)-->|1|F2 s(s)-->|1|F3 s(s)-->|1|F4 s(s)-->|1|F5 E6-->|1|t(t) E7-->|1|t(t) E8-->|1|t(t) E9-->|1|t(t) E10-->|1|t(t) E11-->|1|t(t) E12-->|1|t(t) E13-->|1|t(t) E14-->|1|t(t) E15-->|1|t(t) F1-->|1|E7 F1-->|1|E8 F2-->|1|E6 F2-->|1|E9 F2-->|1|E10 F3-->|1|E7 F3-->|1|E8 F4-->|1|E7 F4-->|1|E8 F5-->|1|E10

其中\(F\)表示外籍飞行员,\(E\)表示英国飞行员。

然后跑一遍\(Dinic\)就得到答案了。

//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;
}

题集

希望这些外籍飞行员里能有中国飞行员。
还是中国飞行员强。

posted @ 2019-09-26 17:39  ANY_HOW  阅读(217)  评论(0编辑  收藏  举报