洛谷P2756 飞行员配对方案问题
题目背景
第二次世界大战时期..
题目描述
英国皇家空军从沦陷国征募了大量外籍飞行员。由皇家空军派出的每一架飞机都需要配备在航行技能和语言上能互相配合的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!’。
输入输出样例
题解
前置知识二分图
这道题思维难度不高,代码比较套路,题面已经透露了算法:二分图匹配
我们只需要将英国飞行员作为左集合中的元素,将外籍飞行员作为右集合的元素,每一种匹配方案连一条边,然后用最大流匹配算法就能解决此题。
关键在于输出方案,匈牙利算法和网络流算法输出方案的方法不同
匈牙利算法
匈牙利算法在过程中就留下了天然的配对数组(match数组),直接输出即可
网络流算法(此处是Dinic)
网络流算法没有天然的配对关系,但我们只要记录每一个点将流量流向了哪一个点,依次输出即可
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int MAXN=1e3+7,MAXM=1e6+7,INF=1e9+7; 4 int N,M,S,T; 5 int to[MAXM*2],nxt[MAXM*2],head[MAXM*2],val[MAXM*2],tp=1; 6 inline void add(int x,int y,int z){ 7 nxt[++tp]=head[x]; 8 head[x]=tp; 9 val[tp]=z; 10 to[tp]=y; 11 } 12 int de[MAXN],gap[MAXN]; 13 inline void bfs(){ 14 queue<int> que; 15 memset(gap,0,sizeof(gap)); 16 memset(de,-1,sizeof(de)); 17 que.push(T); 18 de[T]=0; 19 gap[0]=1; 20 while(que.size()){ 21 int ii=que.front(); 22 que.pop(); 23 for(int i=head[ii];i;i=nxt[i]){ 24 if(de[to[i]]!=-1){ 25 continue; 26 } 27 de[to[i]]=de[ii]+1; 28 gap[de[to[i]]]++; 29 que.push(to[i]); 30 } 31 } 32 } 33 int cur[MAXN],maxflow; 34 int dfs(int x,int flow){ 35 if(x==T){ 36 maxflow+=flow; 37 return flow; 38 } 39 int used=0; 40 for(int i=cur[x];i;i=nxt[i]){ 41 cur[x]=i; 42 if(val[i]&&de[to[i]]+1==de[x]){ 43 int ii=dfs(to[i],min(flow-used,val[i])); 44 if(ii){ 45 used+=ii; 46 val[i]-=ii; 47 val[i^1]+=ii; 48 if(used==flow){ 49 return used; 50 } 51 } 52 } 53 } 54 gap[de[x]]--; 55 if(!gap[de[x]]){ 56 de[S]=N+3; 57 } 58 de[x]++; 59 gap[de[x]]++; 60 return used; 61 } 62 int main(){ 63 scanf("%d%d",&M,&N); 64 S=N+1; 65 T=N+2; 66 for(int i=1;i<=M;i++){ 67 add(S,i,1); 68 add(i,S,0); 69 } 70 for(int i=M+1;i<=N;i++){ 71 add(i,T,1); 72 add(T,i,0); 73 } 74 while(1){ 75 int ii,jj; 76 scanf("%d%d",&ii,&jj); 77 if(ii==-1&&jj==-1){ 78 break; 79 } 80 add(ii,jj,1); 81 add(jj,ii,0); 82 } 83 bfs(); 84 while(de[S]<N+2){ 85 memcpy(cur,head,sizeof(cur)); 86 dfs(S,INF); 87 } 88 if(!maxflow){ 89 printf("No Solution!"); 90 }else{ 91 printf("%d\n",maxflow); 92 for(int i=1;i<=M;i++){ 93 for(int j=head[i];j;j=nxt[j]){ 94 if(to[j]!=T&&to[j]!=S&&val[j^1]){ 95 printf("%d %d\n",i,to[j]); 96 } 97 } 98 } 99 } 100 return 0; 101 }