P2756 飞行员配对方案问题
题目背景
第二次世界大战时期..
题目描述
英国皇家空军从沦陷国征募了大量外籍飞行员。由皇家空军派出的每一架飞机都需要配备在航行技能和语言上能互相配合的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
这个题最直接的就是匈牙利算法,很好用,也很快。
#include<stdio.h>
#include<string.h>
const int MAXN=101;
bool mapp[MAXN][MAXN];
bool vis[MAXN];
int pre[MAXN];
int m,n;
bool find(int x)
{
for(int i=1;i<=n;i++)
{
if(mapp[x][i]==true&&vis[i]==false)
{
vis[i]=true;
if(pre[i]==0||find(pre[i]))
{
pre[i]=x;
pre[x]=i;//此处将通过的边信息存储下来。
return true;
}
}
}
return false;
}
int main()
{
scanf("%d%d",&m,&n );
int a,b;
memset(mapp,false , sizeof(mapp));
while(scanf("%d%d",&a,&b)&&a!=-1&&b!=-1)
{
mapp[a][b]=true;
}
int ans=0;
memset(pre,0 , sizeof(pre));
for(int i=1;i<=m;i++)
{
memset(vis,false , sizeof(vis));
if(find(i)) ans++;
}
if(ans==0)
puts("No Solution!");
else
{
printf("%d\n",ans );
for(int i=1;i<=m;i++)
{
if(pre[i])
printf("%d %d\n",i,pre[i] );
}
}
return 0;
}
当然也可以网络流,飞行员和飞行员连接,容量是一,再创建源点和汇点与飞行员连接,容量还是1,这是保证每个外籍飞行员只能与一个英国飞行员连接。我用的是Ek算法。
#include<stdio.h>
#include<string.h>
#include<queue>
#include<algorithm>
#include<vector>
using namespace std;
const int MAXN=205;
const int INF=0x3f3f3f3f;
int n,m;
int mapp[MAXN][MAXN];
bool vis[MAXN];
int pre[MAXN];
int ma[MAXN];
bool bfs(int s,int e)
{
int p;
memset(pre,-1 , sizeof(pre));
memset(vis,false , sizeof(vis));
queue<int>q;
q.push(s);
while(!q.empty())
{
p=q.front();
q.pop();
for(int i=0;i<=m+n+1;i++)
{
if(!vis[i]&&mapp[p][i]>0)
{
vis[i]=true;
pre[i]=p;
if(i==e)
return true;
q.push(i);
}
}
}
return false;
}
int EK(int s,int e)
{
int flow=0,d;
while(bfs(s,e))
{
d=INF;
for(int i=e;i!=s;i=pre[i])
{
if(i!=e&&pre[i]!=s&&i!=s&&pre[i]!=e)
{
ma[pre[i]]=i;//此处存下连接信息
}
d=min(d,mapp[pre[i]][i]);
}
for (int i =e; i !=s ;i=pre[i])
{
mapp[pre[i]][i]-=d;
mapp[i][pre[i]]+=d;
}
flow+=d;
}
return flow;
}
int main()
{
scanf("%d%d",&m,&n);
int x,y;
memset(mapp,0,sizeof(mapp));
memset(ma, false, sizeof(ma));
while(scanf("%d%d",&x,&y)&&x!=-1&&y!=-1)
{
mapp[x][y+m]+=1;
}
int e=m+n+1;
for(int i=1;i<=m;i++)
mapp[0][i]+=1;
for(int i=m+1;i<e;i++)
mapp[i][e]+=1;
int ans=EK(0,e);
if(ans==0)
{
printf("No Solution!\n");
}
else
{
printf("%d\n",ans );
for(int i=1;i<=m;i++)
{
if(ma[i])
printf("%d %d\n",i,ma[i]-m);
}
}
return 0;
}