网络流基本知识就不在这里阐述了。
算法实现题 8-1 飞行员配对方案问题
问题描述:
第二次世界大战时期,英国皇家空军从沦陷国征募了大量外籍飞行员。由皇家空军派出
的每一架飞机都需要配备在航行技能和语言上能互相配合的 2 名飞行员, 其中 1 名是英国飞
行员,另 1 名是外籍飞行员。在众多的飞行员中,每一名外籍飞行员都可以与其他若干名英
国飞行员很好地配合。如何选择配对飞行的飞行员才能使一次派出最多的飞机。对于给定的
外籍飞行员与英国飞行员的配合情况,试设计一个算法找出最佳飞行员配对方案,使皇家空
军一次能派出最多的飞机。
编程任务:
对于给定的外籍飞行员与英国飞行员的配合情况,编程找出一个最佳飞行员配对方案,
使皇家空军一次能派出最多的飞机。
数据输入:
由文件 input.txt 提供输入数据。文件第 1 行有 2 个正整数 m 和 n。n 是皇家空军的飞行
员总数(n<100);m 是外籍飞行员数。外籍飞行员编号为 1~m;英国飞行员编号为 m+1~n。
接下来每行有 2 个正整数 i 和 j,表示外籍飞行员 i 可以和英国飞行员 j 配合。文件最后以 2
个-1 结束。
结果输出:
程序运行结束时,将最佳飞行员配对方案输出到文件 output.txt 中。第 1 行是最佳飞行
员配对方案一次能派出的最多的飞机数 M。接下来 M 行是最佳飞行员配对方案。每行有 2
个正整数 i 和 j,表示在最佳飞行员配对方案中,飞行员 i 和飞行员 j 配对。
如果所求的最佳飞行员配对方案不存在,则输出‘No Solution!’ 。
我们先画个图~
我们发现这题就是求二分图的最大匹配?
好吧,你有两个选择
1.敲KM
2.外籍飞行员放在x集合里面,英国王牌飞行员放在y集合里面,设立源点S,汇点T,S向每个x集合里面的点连一条容量为1的边(限制每个点只能连出一条边),y集合里面每个点连一条容量为1的点到T,每个配对连容量为1的边,跑最大流。
网络流第一个建模。。还体验了一把输出方案的可怕之处。(从此立下没有SPJ || 唯一解 不打方案的flag!)
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<cmath> 5 #include<queue> 6 7 #define maxn 102 8 9 using namespace std; 10 11 int dis[maxn],dp[maxn][maxn],m; 12 13 bool DFS() 14 { 15 memset(dis,-1,sizeof(dis)); 16 dis[0]=1; 17 queue<int>q; 18 q.push(0); 19 while(!q.empty()) 20 { 21 int u=q.front(); 22 if(u==m+1)break; 23 q.pop(); 24 for(int i=0;i<=m+1;i++)if(dis[i]==-1&&dp[u][i]>0){ 25 dis[i]=dis[u]+1; 26 q.push(i); 27 } 28 } 29 if(dis[m]==-1)return 0; 30 else return 1; 31 } 32 33 int find(int poi,int low) 34 { 35 int a; 36 if(poi==m+1)return low; 37 for(int i=0;i<=m+1;i++)if(dp[poi][i]>0&&dis[i]==dis[poi]+1){ 38 a=find(i,min(low,dp[poi][i])); 39 if(a){ 40 dp[poi][i]-=a; 41 dp[i][poi]+=a; 42 return a; 43 } 44 } 45 return 0; 46 } 47 48 int main() 49 { 50 int a,n,x,y,ans=0; 51 scanf("%d%d%d%d",&n,&m,&x,&y); 52 while(x!=-1&&y!=-1) 53 { 54 dp[x][y]=1; 55 scanf("%d%d",&x,&y); 56 } 57 for(int i=1;i<=n;i++) 58 dp[0][i]=1; 59 for(int i=n+1;i<=m;i++) 60 dp[i][m+1]=1; 61 while(DFS()) 62 { 63 a=find(0,99999999); 64 while(a) 65 { 66 ans+=a; 67 a=find(0,99999999); 68 } 69 } 70 printf("%d",ans); 71 return 0; 72 }