您的位置:首页 > 理论基础 > 计算机网络

飞行员配对问题[网络流24题之1]

2016-05-18 13:39 330 查看

问题描述:

第二次世界大战时期,英国皇家空军从沦陷国征募了大量外籍飞行员。由皇家空军派出的每一架飞机都需要配备在航行技能和语言上能互相配合的 2 名飞行员, 其中 1 名是英国飞行员,另 1 名是外籍飞行员。在众多的飞行员中,每一名外籍飞行员都可以与其他若干名英国飞行员很好地配合。如何选择配对飞行的飞行员才能使一次派出最多的飞机。对于给定的外籍飞行员与英国飞行员的配合情况,试设计一个算法找出最佳飞行员配对方案,使皇家空军一次能派出最多的飞机。

编程任务:

对于给定的外籍飞行员与英国飞行员的配合情况,编程找出一个最佳飞行员配对方案,使皇家空军一次能派出最多的飞机。

数据输入:

文件第 1 行有 2个正整数 m 和 n 。n 是皇家空军的飞行员总数( n<100 ); m 是外籍飞行员数。外籍飞行员编号为 1 ~ m ;英国飞行员编号为 m+1 ~ n 。

接下来每行有 2 个正整数 i 和 j ,表示外籍飞行员 i 可以和英国飞行员 j 配合。文件最后以 2 个 −1 结束。

结果输出 :

第 1 行是最佳飞行员配对方案一次能派出的最多的飞机数 M 。接下来 M 行是最佳飞行员配对方案。每行有 2 个正整数 i 和 j ,表示在最佳飞行员配对方案中,飞行员 i 和飞行员 j 配对。

如果所求的最佳飞行员配对方案不存在,则输出 No Solution! 。

输入文件示例 :

5 10

1 7

1 8

2 6

2 9

2 10

3 7

3 8

4 7

4 8

5 10

-1 -1

输出文件示例

4

1 7

2 9

3 8

5 10

分析 :

这个题目是一个经典的网络流问题,若把英国飞行员和外籍飞行员之间连一条边就是一个多源点多汇点的网络流问题,建模过程如下

1 :把配对的飞行员之间连一条容量为 1 的边

2 :新增一个源 S ,把 S 与外籍飞行员之间连一条容量为 1 的边

3 :新增一个汇 T ,把 T 与英国飞行员之间连一条容量为 1 的边

最后求出图中的最大流即为最多配对数。求最大流我用的是 dinic 算法其中因为任意一个飞行员只能与其他飞行员配对一次,所以边的容量为 1 。

至于输出配对方案的话,直接在图中寻找那些流量为 1 的边即可。

代码 :

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;

const int inf = 0x3f3f3f3f;

int n,m;
int tot = 1;
int ans;
int c[1147];
int head[1147],nxt[2247],to[2247],wei[2247];
int cur[1147];
queue<int> que;

int read();
void add(int,int);
bool bfs();
int dinic(int,int);

int main(){

n=read();m=read();
for(int i=1;i<=n;++i)
add(1,i+1);
for(int i=n+1;i<=m;++i)
add(i+1,m+2);
int a,b;
a=read();b=read();
while(a!=-1 && b!=-1){
a++;b++;
add(a,b);
a=read();b=read();
}

int flag;
while(bfs()){
flag = 1;
while(flag){
memcpy(cur,head,sizeof head);
flag = dinic(1,inf);
ans += flag;
}
}

if(ans){
printf("%d",ans);
for(int i=head[1];i;i=nxt[i])
if(!wei[i])
for(int j=head[to[i]];j;j=nxt[j])
if(!wei[j]){
printf("\n%d %d",to[i],to[j]);
break;
}
}
else
printf("No Solution!");

return 0;

}

int read(){

int in = 0;
int flag = 1;
char ch = getchar();

while(ch>'9'||ch<'0'){
if(ch=='-'){
ch = getchar();
flag = -1;
break;
}
ch = getchar();
}
while(ch>='0'&&ch<='9'){
in = in*10+ch-'0';
ch = getchar();
}

return in*flag;

}

void add(int from,int tp){
++tot;nxt[tot]=head[from];head[from]=tot;to[tot]=tp;wei[tot]=1;
++tot;nxt[tot]=head[tp];head[tp]=tot;to[tot]=from;wei[tot]=0;
}

bool bfs(){

int now;
memset(c,0,sizeof c);
que.push(1);
c[1] = 1;
do{
now = que.front();
for(int i=head[now];i;i=nxt[i])
if(!c[to[i]] && wei[i]){
c[to[i]] = c[now]+1;
que.push(to[i]);
}
que.pop();
}while(!que.empty());

return c[m+2];

}

int dinic(int place,int low){

if(place == m+2)
return low;

int lower;
for(int &i=cur[place];i;i=nxt[i])
if(c[to[i]]==c[place]+1 && wei[i]){
lower = dinic(to[i],min(low,wei[i]));
if(lower){
wei[i] -= lower;
wei[i^1] += lower;
return lower;
}
}

return 0;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息