洛谷P2756 飞行员配对方案问题

题目:https://www.luogu.org/problemnew/show/2756

题目背景

第二次世界大战时期..

题目描述

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

解析

网络流24题之一orz。

二分图最大匹配。

 

S和外籍连容量为1的边。

英籍和T连容量为1的边。

外籍和英籍能一块的连容量为1的边。

跑最大流,得最大数量。

 

查找连接英籍与外籍飞行员的边。

如果满流,则输出两人编号。

 

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<algorithm>
  4 #include<cstring>
  5 #include<cmath>
  6 #include<queue>
  7 #include<vector>
  8 #define inf 2<<29
  9 #define S 0
 10 #define T 300
 11 using namespace std;
 12 
 13 struct line{
 14     int from,to;
 15     int cap,flow;
 16 };
 17 vector<line> edge;
 18 vector<int> G[330];
 19 
 20 int m,n;
 21 int x,y;
 22 int ans,cnt;
 23 
 24 int vis[330];
 25 int cur[330];
 26 int dis[330];
 27 
 28 void addedge(int from,int to,int cap){
 29     edge.push_back((line){from,to,cap,0});
 30     edge.push_back((line){to,from,0,0});
 31     int m=edge.size();
 32     G[from].push_back(m-2);
 33     G[to].push_back(m-1);
 34 }
 35 
 36 bool bfs(){
 37     memset(vis,0,sizeof(vis));
 38     queue<int> q;
 39     q.push(S);
 40     dis[S]=0;
 41     vis[S]=1;
 42     while (!q.empty()){
 43         int now=q.front();
 44         q.pop();
 45         for (int i=0;i<G[now].size();++i){
 46             line e=edge[G[now][i]];
 47             if (!vis[e.to]&&e.cap>e.flow){
 48                 q.push(e.to);
 49                 vis[e.to]=1;
 50                 dis[e.to]=dis[now]+1;
 51             }
 52         }
 53     }
 54     return vis[T];
 55 }
 56 
 57 int dfs(int x,int a){
 58     if (x==T||a==0) return a;
 59     int f,flow=0;
 60     for (int& i=cur[x];i<G[x].size();++i){
 61         line& e=edge[G[x][i]];
 62         if ((dis[e.to]==dis[x]+1)&&(f=dfs(e.to,min(a,e.cap-e.flow)))){
 63             flow+=f;
 64             a-=f;
 65             e.flow+=f;
 66             edge[G[x][i]^1].flow-=f;
 67             if (!a) break;
 68         }
 69     }
 70     return flow;
 71 }
 72 
 73 void dinic(){
 74     while (bfs()){
 75         memset(cur,0,sizeof(cur));
 76         ans+=dfs(S,inf);
 77     }
 78 }
 79 
 80 int main(){
 81     scanf("%d%d",&m,&n);
 82     for (int i=1;i<=m;++i)
 83       addedge(S,i,1);
 84     for (int i=1;i<=n;++i)
 85       addedge(i+m,T,1);
 86     scanf("%d%d",&x,&y);
 87     while (x!=-1&&y!=-1){
 88         addedge(x,y+m,1);
 89         scanf("%d%d",&x,&y);
 90     }
 91     dinic();
 92     if (ans==0){
 93         printf("No Solution!");
 94         return 0;
 95     }
 96     printf("%d\n",ans);
 97     
 98     int maxsize=edge.size(); 
 99     
100     for (int i=0;i<maxsize;i+=2){
101         if (edge[i].flow==1&&
102             edge[i].from!=S&&edge[i].to!=T){
103                 printf("%d %d\n",edge[i].from,edge[i].to-m);
104                 ++cnt;
105                 if (cnt==ans) break;
106             }
107     }
108     return 0;
109 }
View Code

 

 

 

 
posted @ 2017-12-17 21:13  lonlyn  阅读(166)  评论(0编辑  收藏  举报