题目描述
英国皇家空军从沦陷国征募了大量外籍飞行员。由皇家空军派出的每一架飞机都需要配备在航行技能和语言上能互相配合的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题,最大匹配问题,对外籍和英建一条流量为1的边,最后在建立超级汇点和超级据点,跑最大流就好了。对于结果我们检查图的边,容量为0的边为选中匹配,去掉超级汇点和超级聚点输出就好了
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+5;
const int INF=9999999;
int s,t,cnt,n,m;//s为源点,t为汇点
struct node{
int from;
int next=-1;//初始化为-1,如果访问到了-1,则需要退出
int to;
int w;
};
int head[maxn],q[maxn],deth[maxn];
node edge[maxn];
void init(){
cnt=-1;
memset(head,-1,sizeof(head));
}
void add(int x,int y,int z){
cnt++;
edge[cnt].from=x;
edge[cnt].to=y;//终点
edge[cnt].next=head[x];//上一条边
edge[cnt].w=z;//边权
head[x]=cnt;//起点
}
int bfs(){
memset(deth,0,sizeof(deth));//deth记录深度
queue<int> q;
while(!q.empty())
q.pop();
deth[s]=1;
q.push(s);
do{
int u=q.front();
q.pop();
for(int i=head[u];i!=-1;i=edge[i].next){
if(edge[i].w>0&&deth[edge[i].to]==0){
deth[edge[i].to]=deth[u]+1;
q.push(edge[i].to);
}
}
}
while(!q.empty());
if(deth[t]!=0)//当汇点的深度不存在时,说明不存在分层图,同时也说明不存在增广路
return 1;
else
return 0;
}
int dfs(int u,int dist){
if(u==t)
return dist;
for(int i=head[u];i!=-1;i=edge[i].next){
if((deth[edge[i].to]==deth[u]+1)&&(edge[i].w!=0)){
int di=dfs(edge[i].to,min(dist,edge[i].w));
if(di>0){
edge[i].w-=di;
edge[i^1].w+=di;
return di;
}
}
}
return 0;//否则说明没有增广路,返回0
}
int dinic(int S,int T){
s=S;t=T;
int ans=0;
while(bfs())
while(int di=dfs(s,INF))
ans+=di;
return ans;
}
int main(){
ios::sync_with_stdio(false);
cin>>n>>m;
int x,y;
init();
while(cin>>x>>y){
if(x==-1&&y==-1) break;
add(x,n+y,1);
add(n+y,x,0);
}
for(int i=1;i<=n;i++){
add(0,i,1);
add(i,0,0);
}
for(int i=1;i<=m;i++){
add(i+n,n+m+1,1);
add(n+m+1,i+n,0);
}
cout<<dinic(0,m+n+1)<<endl;
for(int i=0;i<=cnt;i+=2){
if(edge[i].w==0&&edge[i].from!=s&&edge[i].to!=t) cout<<edge[i].from<<" "<<edge[i].to-n<<endl;
}
return 0;
}