洛谷:P2756 飞行员配对方案问题(网络流24题 最大流,匈牙利匹配)
https://www.luogu.org/problemnew/show/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
网络最大流 :
在左边建立一个超级源点,在右边建立一个超级汇点,转化成最大流问题,再找出正向流为0,逆向流为1的两个点即为相匹配的点。
#include <stdio.h>
#include <string.h>
#include <vector>
#include <algorithm>
using namespace std;
#define N 120
int e[N][N], book[N], l[N], n, m, inf=99999999;
struct edge{
int to;
int cap;
int rev;
};
vector<edge>G[N];
void add (int from, int to)
{
int cap=1;
G[from].push_back((edge){to, cap, G[to].size()});
G[to].push_back((edge){from, 0, G[from].size()-1});
}
int dfs(int v, int t, int f)
{
int i;
if(v==t)
return f;
book[v]=1;
for(i=0; i<G[v].size(); i++)
{
edge &e=G[v][i];
if(!book[e.to] && e.cap>0){
int d=dfs(e.to, t, min(f, e.cap));
if(d>0)
{
e.cap-=d;
G[e.to][e.rev].cap+=d;
return d;
}
}
}
return 0;
}
int max_flow(int s, int t)
{
int flow=0;
while(1)
{
memset(book, 0, sizeof(book));
int f=dfs(s, t, inf);
if(f==0)
return flow;
flow+=f;
}
}
int main()
{
int i, j, u, v, w, ans;
scanf("%d%d", &m, &n);
for(i=1; i<=m; i++)
add(0, i);
for(i=m+1; i<=n; i++)
add(i, n+1);
while(1)
{
scanf("%d%d", &u, &v);
if(u==-1 && v==-1)
break;
add(u, v);
}
for(i=1; i<=n; i++)
for(j=1; j<=n; j++)
e[i][j]=2;
ans=max_flow(0, n+1);
if(!ans)
printf("No Solution!\n");
else
{
printf("%d\n", ans);
for(i=1; i<=n; i++)
{
for(j=0; j<G[i].size(); j++)
{
if(e[i][G[i][j].to]==2)
e[i][G[i][j].to]=G[i][j].cap;
}
}
for(i=1; i<=m; i++)
for(j=m+1; j<=n; j++)
if(e[i][j]==0 && e[j][i]==1)
printf("%d %d\n", i, j);
}
return 0;
}
匈牙利算法:
#include <stdio.h>
#include <string.h>
#define N 220
int e[N][N], march[N], book[N], n, m;
int dfs(int u)
{
int v;
for(v=m+1; v<=n; v++)
{
if(e[u][v] && !book[v])
{
book[v]=1;
if(march[v]==0 || dfs(march[v]))
{
march[v]=u;
return 1;
}
}
}
return 0;
}
int main()
{
int i, j, u, v, ans;
memset(e, 0, sizeof(e));
scanf("%d%d", &m, &n);
while(scanf("%d%d", &u, &v)!=EOF)
{
if(u==-1 && v==-1)
break;
e[u][v]=1;
}
ans=0;
for(i=1; i<=m; i++)
{
memset(book, 0, sizeof(book));
if(dfs(i))
ans++;
}
if(ans==0)
printf("No Solution!\n");
else{
printf("%d\n", ans);
for(i=m+1; i<=n; i++)
if(march[i])
printf("%d %d\n", march[i], i);
}
return 0;
}