网络流二十四题之一 —— 飞行员配对方案问题(AIR)

注:本题在Codevs上有原题,但因为缺少Special Judge而无法通过。请想要数据的Oier通过邮箱联系我(邮箱请见左上角)。


飞行员配对方案问题


Description

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


Input

由文件 input.txt 提供输入数据。
文件第 1 行有 2 个正整数 m n
n 是皇家空军的飞行员总数 (n<100) m 是外籍飞行员数。
外籍飞行员编号为 1~ m ;英国飞行员编号为 m+1~ n
接下来每行有 2 个正整数 i j,表示外籍飞行员 i 可以和英国飞行员 j 配合。
文件最后以 2 1 结束。


Output

程序运行结束时,将最佳飞行员配对方案输出到文件 output.txt 中。
1 行是最佳飞行员配对方案一次能派出的最多的飞机数 M
接下来 M 行是最佳飞行员配对方案。
每行有 2 个正整数 i j,表示在最佳飞行员配对方案中,飞行员 i 和飞行员 j 配对。
如果所求的最佳飞行员配对方案不存在,则输出“ NoSolution!


Sample Input

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


Sample Output

4
1 7
2 9
3 8
5 10


Solution

本题就是一个典型的二分图最大匹配问题,可以当作最大流问题来解决。
我给出的求最大流的代码是 Dinic 算法(输出方案的部分我图省事,打得比较丑)。


[cpp]
  1. #include <iostream>  
  2. #include <cstring>  
  3. #include <cstdio>  
  4. #include <queue>  
  5. #include <algorithm>  
  6.   
  7. #define Min(a,b) ((a)<(b)?(a):(b))  
  8.   
  9. using namespace std;  
  10.   
  11. struct ans{  
  12.     int a,b;  
  13. }ANS[1000];  
  14.   
  15. bool cmp(ans a,ans b){  
  16.     return a.a<b.a||(a.a==b.a&&a.b<b.b);  
  17. }  
  18.   
  19. const int INF=0x3f3f3f3f;  
  20. const int MAXN=10000;  
  21.   
  22. queue<int>q;  
  23. int data[MAXN*2],weight[MAXN*2];  
  24. int nxt[MAXN*2],head[MAXN],dis[MAXN],from[MAXN*2];  
  25. int n,m,cnt,s,t,ANSS;  
  26.   
  27. void add(int x,int y,int z){  
  28.     from[cnt]=x;nxt[cnt]=head[x];data[cnt]=y;weight[cnt]=z;head[x]=cnt++;  
  29.     from[cnt]=y;nxt[cnt]=head[y];data[cnt]=x;weight[cnt]=0;head[y]=cnt++;   
  30. }  
  31.   
  32. bool BFS(){  
  33.     memset(dis,-1,sizeof dis);  
  34.     dis[s]=0;  
  35.     q.push(s);  
  36.     while(!q.empty()){  
  37.         int now=q.front();  
  38.         q.pop();  
  39.         for(int i=head[now];i!=-1;i=nxt[i])if(dis[data[i]]<0&&weight[i]){  
  40.             dis[data[i]]=dis[now]+1;  
  41.             q.push(data[i]);  
  42.         }  
  43.     }  
  44.     return dis[t]>0;  
  45. }  
  46.   
  47. int dfs(int now,int low){  
  48.     if(now==t)return low;  
  49.     int Low;  
  50.     for(int i=head[now];i!=-1;i=nxt[i]){  
  51.         if(weight[i]&&dis[data[i]]==dis[now]+1){  
  52.             if(Low=dfs(data[i],Min(low,weight[i]))){  
  53.                 weight[i]-=Low;  
  54.                 weight[i^1]+=Low;  
  55.                 return Low;  
  56.             }  
  57.         }  
  58.     }  
  59.     return 0;  
  60. }  
  61.   
  62. int main(){  
  63.     freopen(”air.in”,“r”,stdin);  
  64.     freopen(”air.out”,“w”,stdout);  
  65.     memset(head,-1,sizeof head);  
  66.     scanf(”%d%d”,&m,&n);  
  67. //  s=1;t=n;  
  68. //  for(int i=1;i<=m;i++){  
  69. //      int x,y,z;  
  70. //      scanf(“%d%d%d”,&x,&y,&z);  
  71. //      add(x,y,z);  
  72. //  }  
  73.     s=100*4;  
  74.     t=100*4+1;  
  75.     int x,y;  
  76.     while(scanf(“%d%d”,&x,&y)!=EOF&&(x!=-1||y!=-1))add(x,y+n-m,1);  
  77.     for(int i=m+1;i<=n;i++){  
  78.         add(i+n-m,i,1);  
  79.         add(i,t,1);  
  80.     }  
  81.     for(int i=1;i<=m;i++)add(s,i,1);  
  82.     int sum=0,flow;  
  83.     while(BFS())  
  84.         while(flow=dfs(s,INF))sum+=flow;  
  85.     if(!sum){  
  86.         printf(”No Solution!”);  
  87.         return 0;  
  88.     }  
  89.     printf(”%d\n”,sum);  
  90.     for(int i=0;i<cnt;i++){  
  91.         if(!weight[i]&&from[i]!=s&&data[i]!=t&&from[i]!=t&&data[i]!=s&&from[i]<data[i]-n+m){  
  92.             ANS[++ANSS].a=from[i];  
  93.             ANS[ANSS].b=data[i]-n+m;  
  94.         }  
  95.     }  
  96.     sort(ANS+1,ANS+ANSS+1,cmp);  
  97.     for(int i=1;i<=ANSS;i++)printf(“%d %d\n”,ANS[i].a,ANS[i].b);  
  98.     return 0;  
  99. }  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值