飞行员配对方案问题
题目描述 Description
第二次世界大战时期,英国皇家空军从沦陷国征募了大量外籍飞行员。由皇家空军派出的每一架飞机都需要配备在航行技能和语言上能互相配合的 2 名飞行员,其中 1 名是英国飞行员,另 1 名是外籍飞行员。在众多的飞行员中,每一名外籍飞行员都可以与其他若干名英国飞行员很好地配合。如何选择配对飞行的飞行员才能使一次派出最多的飞机。对于给定的外籍飞行员与英国飞行员的配合情况,试设计一个算法找出最佳飞行员配对方案,使皇家空军一次能派出最多的飞机。
对于给定的外籍飞行员与英国飞行员的配合情况,编程找出一个最佳飞行员配对方案,使皇家空军一次能派出最多的飞机。
输入描述 Input Description
第 1 行有 2 个正整数 m和 n。n 是皇家空军的飞行员总数(n<100);m 是外籍飞行员数。外籍飞行员编号为 1~m;英国飞行员编号为 m+1~n。接下来每行有 2 个正整数 i 和 j,表示外籍飞行员 i 可以和英国飞行员 j 配合。文件最后以 2个-1 结束。
输出描述 Output Description
第 1 行是最佳飞行员配对方案一次能派出的最多的飞机数 M。
样例输入 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:匈牙利算法——二分图的最大匹配,但是时间复杂度o(nm)过高
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
bool line[1000][1000];
int used[1000],girl[1000],n,m,ans;
bool find(int x)
{
int i,j;
for (j=1;j<=m;j++)
{
if (line[x][j]==true && used[j]==false)
{
used[j]=1;
if (girl[j]==0 || find(girl[j]))
{
girl[j]=x;
return true;
}
}
}
return false;
}
int main()
{
scanf("%d%d",&n,&m);
int x,y;
scanf("%d%d",&x,&y);
while (x!=-1&&y!=-1)
{
line[x][y-n]=true;
scanf("%d%d",&x,&y);
}
m-=n;
for (int i=1;i<=n;i++)
{
memset(used,0,sizeof(used));
if (find(i)) ans++;
}
printf("%d",ans);
}
有关匈牙利算法原理的解释建议去看看网上的趣解匈牙利算法
算法2:网络流,dinic算法十分适合二分图,o(sqrt(n)m)
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
int e[110],f[110],point[210],next[2000003],v[2000003],remain[2000003];
int deep[210],cur[210],n,m,tot;
const int inf=1e9;
void add(int x,int y)
{
tot++; next[tot]=point[x]; point[x]=tot; v[tot]=y; remain[tot]=1;
tot++; next[tot]=point[y]; point[y]=tot; v[tot]=x; remain[tot]=0;
}
bool bfs(int s,int t)
{
memset(deep,0x7f,sizeof(deep));
for (int i=s;i<=t;i++)
cur[i]=point[i];
deep[0]=0;
queue<int> p;
p.push(s);
while (!p.empty())
{
int now=p.front(); p.pop();
for (int i=point[now];i!=-1;i=next[i])
if (deep[v[i]]>inf&&remain[i])
{
deep[v[i]]=deep[now]+1; p.push(v[i]);
}
}
return deep[t]<inf;
}
int dfs(int now,int t,int limit)
{
if (!limit||now==t) return limit;
int flow=0,f;
for (int i=cur[now];i!=-1;i=next[i])
{
cur[now]=i;
if (deep[now]+1==deep[v[i]]&&(f=dfs(v[i],t,min(limit,remain[i]))))
{
flow+=f; limit-=f; remain[i]-=f; remain[i^1]+=f;
if (!limit) break;
}
}
return flow;
}
int dinic (int s,int t)
{
int ans=0;
while (bfs(s,t))
ans+=dfs(s,t,inf);
return ans;
}
int main()
{
scanf("%d%d",&n,&m);
int x,y;
tot=-1; memset(point,-1,sizeof(point)); memset(next,-1,sizeof(next));
for (int i=1;i<=n;i++)
add(0,i);
for (int i=n+1;i<=m;i++)
add(i,m+1);
scanf("%d%d",&x,&y);
while (x!=-1&&y!=-1)
{
add(x,y);
scanf("%d%d",&x,&y);
}
printf("%d",dinic(0,m+1));
}