文章目录
##题目大意:
只要外籍飞行员与英籍飞行员匹配就可以驾驶一架飞机,共有n个飞行员,其中有m个外籍的,问最多有多少对匹配的飞行员(一个外籍一个英籍)
##解题思路:
方法:网络流——最大流
匈牙利算法
这里用网络流——最大流
首先建一个源点和一个汇点,源点与外籍飞行员间建立一条有向边(外籍飞行员方向),汇点与英籍飞行员建立一条有向边(英籍飞行员方向)。
所有边的容量为1,也就是说流量最多为1。
然后求最大流,这个最大流就是最大匹配。
##源程序:
#include<cstdio>
#include<iostream>
using namespace std;
int sum,b[102],f[102][102];
int a[102][102],u[102],v[102],ans,n,m,x,y;
bool find(int k)//找增广路
{
if (k==m+1) return 1;
//如果已经找到就退出(废话)
for (int i=0;i<=m+1;i++)
if (b[i]==-1&&((f[k][i]==0&&a[k][i])||f[i][k]))
//b[i]==-1说明没人与他匹配
//f[k][i]==0也就是说可以与他匹配
//a[k][i]是匹配前提,要能配对才可以"合作"
//f[i][k]是逆向边,如果是逆向边而且已经反向"流"了
//就可以合作
{
b[i]=k;
//记录前驱
if (find(i)) return 1;
//递归判断是否是增广路
}
return 0;
}
void update()//更新
{
int l=m+1;//从后往前去边
while (l)
{
if (a[b[l]][l]) f[b[l]][l]++;
//流量+1
if (a[l][b[l]]) f[l][b[l]]--;
//正向流和逆向流抵消
l=b[l];
//继续往前搜
}
ans++;
}
int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++)
a[0][i]=1;
//源点连外籍飞行员
for (int j=n+1;j<=m+1;j++)
a[j][m+1]=1;
//英籍飞行员连汇点
while (x!=-1&&y!=-1)
scanf("%d%d",&x,&y),a[x][y]=1;
//读入,建图(边)
for (int i=0;i<=m+1;i++) b[i]=-1;
b[0]=0;
//初始化
while (find(0))//找增广路
{
update();
for (int i=1;i<=m+1;i++) b[i]=-1;
}
if (!ans)
{
puts("No Solution!");
return 0;
}//如果没有(其实不打也AC,只是打了严谨一些)就输出No Solution!
printf("%d\n",ans);
//输出匹配总数
for (int i=1;i<=n;i++)
{
for (int j=n+1;j<=m;j++)
if (f[i][j]) {printf("%d %d\n",i,j);break;}
//枚举找每一对匹配的飞行员
}
}