题目链接: luogu 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就OK了,注意这里不能使用vis[i][j]表示i到j个飞行员是否可行,因为有退流操作.
下面是vis[i][j]判断是否可行的代码,WA 63.
#include "iostream"
#include "cstdio"
#include "queue"
#include "algorithm"
#include "cstring"
const int maxN = 1e2 + 7;
const int maxM = 1e4 + 5;
const int inf = 0x7fffffff;
using namespace std;
int n,m,s,t;
int head[maxN];
int nex[maxM];
int v[maxM];
int w[maxM];
int dep[maxN];
int num;
bool vis[maxN][maxN];
void init() {
s = 1;t = n + 2;
num = -1;
memset(head,-1,sizeof(head));
return;
}
inline int read() {
int x = 0,f = 1;char c = getchar();
while(c < '0' || c > '9') {if(c == '-')f = -1;c = getchar();}
while(c >= '0' && c <= '9') {x = x * 10 + c - '0';c = getchar();}
return x * f;
}
void add_Node(int U,int V,int W) {
v[++num] = V;
w[num] = W;
nex[num] = head[U];
head[U] = num;
}
void add(int u,int v,int w) {
add_Node(u,v,w);
add_Node(v,u,0);
}
bool bfs() {
memset(dep,0,sizeof(dep));
queue<int>q;
while(!q.empty())
q.pop();
q.push(s);
dep[s] = 1;
do{
int p = q.front();q.pop();
for(int i = head[p];i != -1;i = nex[i]) {
if(w[i] && dep[v[i]] == 0) {
q.push(v[i]);
dep[v[i]] = dep[p] + 1;
}
}
}while(!q.empty());
if(dep[t]) return true;
return false;
}
int dfs(int now,int dist) {
if(now == t) return dist;
for(int i = head[now];i != -1;i = nex[i]) {
if(dep[v[i]] == dep[now] + 1 && w[i] && vis[now][v[i]] == false) {
int di = dfs(v[i],min(dist,w[i]));
if(di) {
w[i] -= di;
w[i ^ 1] += di;
vis[now][v[i]] = true;
return di;
}
}
}
return 0;
}
void Dinic() {
int Ans = 0;
while(bfs()) {
while(int d = dfs(s,inf)) {
Ans += d;
}
}
printf("%d\n",Ans);
for(int i = 2;i <= m + 1;++ i) {
for(int j = m + 2;j <= n + 1;++ j) {
if(vis[i][j]) {
printf("%d %d\n",i - 1,j - 1);
break;
}
}
}
return;
}
int main() {
scanf("%d%d",&m,&n);
init();
for(int i = 2;i <= m + 1;++ i)
add(s,i,1);
for(int i = m + 2;i <= n + 1;++ i)
add(i,t,1);
int u,v;
while(scanf("%d%d",&u,&v) && u != -1)
add(u + 1,v + 1,1);
Dinic();
return 0;
}
下面是AC代码
#include "iostream"
#include "cstdio"
#include "queue"
#include "algorithm"
#include "cstring"
const int maxN = 1e2 + 7;
const int maxM = 1e4 + 5;
const int inf = 0x7fffffff;
using namespace std;
int n,m,s,t;
int head[maxN];
int nex[maxM];
int v[maxM];
int w[maxM];
int dep[maxN];
int num;
bool vis[maxN][maxN];
void init() {
s = 1;t = n + 2;
num = -1;
memset(head,-1,sizeof(head));
return;
}
inline int read() {
int x = 0,f = 1;char c = getchar();
while(c < '0' || c > '9') {if(c == '-')f = -1;c = getchar();}
while(c >= '0' && c <= '9') {x = x * 10 + c - '0';c = getchar();}
return x * f;
}
void add_Node(int U,int V,int W) {
v[++num] = V;
w[num] = W;
nex[num] = head[U];
head[U] = num;
}
void add(int u,int v,int w) {
add_Node(u,v,w);
add_Node(v,u,0);
}
bool bfs() {
memset(dep,0,sizeof(dep));
queue<int>q;
while(!q.empty())
q.pop();
q.push(s);
dep[s] = 1;
do{
int p = q.front();q.pop();
for(int i = head[p];i != -1;i = nex[i]) {
if(w[i] && dep[v[i]] == 0) {
q.push(v[i]);
dep[v[i]] = dep[p] + 1;
}
}
}while(!q.empty());
if(dep[t]) return true;
return false;
}
int dfs(int now,int dist) {
if(now == t) return dist;
for(int i = head[now];i != -1;i = nex[i]) {
if(dep[v[i]] == dep[now] + 1 && w[i] && vis[now][v[i]] == false) {
int di = dfs(v[i],min(dist,w[i]));
if(di) {
w[i] -= di;
w[i ^ 1] += di;
vis[now][v[i]] = true;
return di;
}
}
}
return 0;
}
void Dinic() {
int Ans = 0;
while(bfs()) {
while(int d = dfs(s,inf)) {
Ans += d;
}
}
printf("%d\n",Ans);
for(int i = 2;i <= m + 1; ++ i ) {
for(int j = head[i];j != -1;j = nex[j]) {
if( w[j] == 0 && v[j] > m + 1) {
printf("%d %d\n",i - 1,v[j] - 1);
break;
}
}
}
return;
}
int main() {
scanf("%d%d",&m,&n);
init();
for(int i = 2;i <= m + 1;++ i)
add(s,i,1);
for(int i = m + 2;i <= n + 1;++ i)
add(i,t,1);
int u,v;
while(scanf("%d%d",&u,&v) && u != -1)
add(u + 1,v + 1,1);
Dinic();
return 0;
}