题目大意:
只要外籍飞行员与英籍飞行员匹配就可以驾驶一架飞机,共有n个飞行员,其中有m个外籍的,问最多有多少对匹配的飞行员(一个外籍一个英籍)
解题思路:
方法:网络流——最大流
匈牙利算法 这里用网络流——最大流 首先建一个源点和一个汇点,源点与外籍飞行员间建立一条有向边(外籍飞行员方向),汇点与英籍飞行员建立一条有向边(英籍飞行员方向)。 所有边的容量为1,也就是说流量最多为1。 然后求最大流,这个最大流就是最大匹配。源程序:
#include#include 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;} //枚举找每一对匹配的飞行员 }}