飞行员配对方案问题(网络流24题)

洛谷题目链接:飞行员配对方案问题

题目背景

第二次世界大战时期..

题目描述

英国皇家空军从沦陷国征募了大量外籍飞行员。由皇家空军派出的每一架飞机都需要配备在航行技能和语言上能互相配合的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!’。

 

输入输出样例

输入样例#1: 
5 10
1 7
1 8
2 6
2 9
2 10
3 7
3 8
4 7
4 8
5 10
-1 -1
输出样例#1: 
4
1 7
2 9
3 8
5 10 

一道网络流的入门题,这篇博客主要是介绍一下模板,并讲一下这道题的做法。
题意大概就是给出一个二分图(左右两边互不相通),然后要求出最大的配对数,可以用匈牙利算法,这里用网络流来做。
那么我们分析一下这个问题,假设我们把本国飞行员放在一边,把外国飞行员放在一边,那么组成一组配对的前提就是从左边有一条边到右边,一个飞行员只能与一个飞行员配对,那么我们在建边的时候就可以把流量设为1,然后把每个配对关系都建一条残量为1的边,跑出来的最大流就是答案。
另外记得仔细读题!!!注意m,n所表示的含义。
  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<string>
  5 using namespace std;
  6 const int inf=2147483647;
  7 const int N=100;
  8 
  9 int s,t,ans=0;
 10 int n,m,cnt=1;
 11 int lev[N+10];
 12 int last[N+10];
 13 int lis[100100];
 14 
 15 struct edge{
 16   int to,next,cap;
 17 }e[2*N*N+10];
 18 
 19 int minn(int a,int b){
 20   if(a>b) return b;
 21   return a;
 22 }
 23 
 24 int gi(){
 25   int ans=0,f=1;char i=getchar();
 26   while(i<'0'||i>'9'){if(i=='-')f=-1;i=getchar();}
 27   while(i<='9'&&i>='0'){ans=(ans<<1)+(ans<<3)+i-'0';i=getchar();}
 28   return ans*f;
 29 }
 30 
 31 int buf[30];
 32 
 33 void write(int x)
 34 {
 35     if (x<0) putchar('-'),x=-x;
 36     buf[0]=0;
 37     while (x) buf[++buf[0]]=x%10,x/=10;
 38     if (!buf[0]) buf[0]=1,buf[1]=0;
 39     while (buf[0]) putchar('0'+buf[buf[0]--]);
 40 }
 41 
 42 void add(int x,int y,int z){
 43   e[++cnt].to=y;
 44   e[cnt].cap=z;
 45   e[cnt].next=last[x];
 46   last[x]=cnt;
 47 }
 48 
 49 bool bfs(){
 50   int head=0,tail=0;
 51   lis[tail++]=s;
 52   memset(lev,-1,sizeof(lev));
 53   lev[s]=0;
 54   while(head<tail){
 55     int x=lis[head++];
 56     for(int i=last[x];i;i=e[i].next){
 57       int to=e[i].to;
 58       if(lev[to]==-1&&e[i].cap){
 59     lev[to]=lev[x]+1;
 60     lis[tail++]=to;
 61       }
 62     }
 63   }
 64   if(lev[t]!=-1) return true;
 65   return false;
 66 }
 67 
 68 int dfs(int x,int flow){
 69   int rest=0;
 70   if(x==t) return flow;
 71   for(int i=last[x];i;i=e[i].next){
 72     int to=e[i].to;
 73     if(lev[to]==lev[x]+1&&e[i].cap){
 74       int f=dfs(to,minn(flow-rest,e[i].cap));
 75     //  if(f){
 76     rest+=f;
 77     e[i].cap-=f;
 78     e[i^1].cap+=f;
 79     //  }
 80       if(rest==flow) return flow;
 81     }
 82   }
 83   if(!rest)lev[x]=-1;
 84   return rest;
 85 }
 86 
 87 int main(){
 88   int x,y;
 89   n=gi();m=gi();
 90   s=0,t=m+1;
 91   for(int i=1;i<=n;i++)
 92     add(0,i,1),add(i,0,0);
 93   for(int i=n+1;i<=m;i++)
 94     add(i,m+1,1),add(m+1,i,0);
 95   while(1){
 96     x=gi();y=gi();
 97     if(x==-1&&y==-1) break;
 98     add(x,y,1);add(y,x,0);
 99   }
100   while(bfs()) ans+=dfs(s,inf);
101   if(ans){
102     printf("%d\n",ans);
103     for(int i=1;i<=n;i++)
104       for(int j=last[i];j;j=e[j].next)
105     if(!e[j].cap&&e[j].to!=0) write(i),putchar(' '),write(e[j].to),putchar('\n');
106   }
107   else printf("No Solution!\n");
108   return 0;
109 }

本来一个简单的模板因为审题不清搞成这个鬼样。。

 
posted @ 2018-03-20 16:45  Brave_Cattle  阅读(381)  评论(0编辑  收藏  举报