网络流24题-飞行员配对方案问题
时空限制1000ms / 128MB
题目背景
第二次世界大战时期..
题目描述
英国皇家空军从沦陷国征募了大量外籍飞行员。由皇家空军派出的每一架飞机都需要配备在航行技能和语言上能互相配合的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!’。
输入输出样例
输出样例:
View Code
4 1 7 2 9 3 8 5 10
最大流。我选择了拆点,其实仔细想想发现拆不拆点都是一样的。
还有一点需要特别特别注意的是判断两点之间是否有流,可以通过判断它的逆向边是否有流来实现。
#include <bits/stdc++.h> using namespace std; const long long INF=LLONG_MAX/2; const int maxn=257; int now_edge=0,S,T; vector<int>edge[maxn]; int dis[maxn],current[maxn]; int fl[maxn][maxn]={0}; struct ss { int v; long long flow; }edg[maxn*maxn]; void addedge(int u,int v,long long flow) { fl[u][v]+=flow; edge[u].push_back(now_edge); edg[now_edge++]=(ss){v,flow}; edge[v].push_back(now_edge); edg[now_edge++]=(ss){u,0}; } bool bfs() { queue<int>q; q.push(S); memset(dis,0,sizeof(dis)); dis[S]=1; while(!q.empty()) { int now=q.front(); q.pop(); int Size=edge[now].size(); for(int i=0;i<Size;i++) { int to=edg[edge[now][i]].v; if(edg[edge[now][i]].flow>0&&dis[to]==0) { dis[to]=dis[now]+1; q.push(to); } } } if(dis[T]==0)return false; return true; } long long dfs(int now,long long maxflow) { if(now==T)return maxflow; int Size=edge[now].size(); for(int i=current[now];i<Size;i++) { current[now]=i; ss &e=edg[edge[now][i]]; if(dis[e.v]==dis[now]+1&&e.flow>0) { long long flow=dfs(e.v,min(maxflow,e.flow)); if(flow!=0) { fl[now][e.v]-=flow; fl[e.v][now]+=flow; e.flow-=flow; edg[edge[now][i]^1].flow+=flow; return flow; } } } return 0; } long long dinic() { long long ans=0; while(bfs()) { long long flow; memset(current,0,sizeof(current)); while(bool(flow=dfs(S,INF)))ans+=flow; } return ans; } int main() { int m,n,a,b; scanf("%d %d",&m,&n); while(scanf("%d %d",&a,&b)==2) { if(a==-1)break; addedge(a*2,b*2-1,1); } for(int i=1;i<=n;i++)addedge(2*i-1,2*i,1); S=2*n+1; T=2*n+2; for(int i=1;i<=m;i++)addedge(S,i*2-1,1); for(int i=m+1;i<=n;i++)addedge(i*2,T,1); long long ans=dinic(); if(ans==0)printf("No Solution!\n"); else { printf("%lld\n",ans); for(int i=1;i<=m;i++) for(int j=m+1;j<=n;j++) if(fl[j*2-1][i*2]) { printf("%d %d\n",i,j); break; } } return 0; }
路漫漫其修远兮,吾将上下而求索