洛谷P2756 飞行员配对方案问题(Dinic算法模板)

题目背景

第二次世界大战时期..

题目描述

英国皇家空军从沦陷国征募了大量外籍飞行员。由皇家空军派出的每一架飞机都需要配备在航行技能和语言上能互相配合的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 

之前看到这道题用匈牙利算法过了一遍,但后来经过讨论区的提醒发现这道题原来是网络流的题目...(惊了Σ(っ °Д °;)っ)

刚好自己刚开始学习网络流,就打了一篇模板出来.

这道题用Dinic算法求解的关键点在于如何建好图(因为是新手,我直接用邻接矩阵了,前向星还不太熟练...)

然后自己定义一个起点一个终点,将起点和所有的外籍飞行员连接起来,然后将终点和所有的皇家飞行员连接起来,最后套一遍模板就行了.

#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
#include<cmath>
using namespace std;
typedef long long ll;
const int maxn = 205;
const int INF = 50000;
int n,m; //n表示皇家空军飞行员,m表示外籍飞行员
int tot; // n+m
ll sum=0;//最终的最大流量
int mp[maxn][maxn];//起点定为0,重点定为tot
int dis[maxn];//深度
bool bfs(){ //s表示起点的位置
	queue<int> q;
	int tmp;
	memset(dis,-1,sizeof(dis));//每次bfs重置一下深度表
	q.push(0);
	dis[0]=1;//起点深度初始化为1 
	while(!q.empty()){
		tmp = q.front();
		q.pop();
		for(int i=1;i<=tot;i++)
			if(mp[tmp][i]>0 && dis[i]==-1){
				q.push(i);
				dis[i] = dis[tmp]+1;
			}
	}
	if(dis[tot]>0) return true;
	return false;
}
int dfs(int s,int mx){//s表示前一点,mx表示最大的
	if(s == tot) return mx;
	int tmp;
	for(int i=1;i<=tot;i++){
		if(mp[s][i] > 0 && dis[i] == dis[s]+1 && (tmp = dfs(i,min(mx,mp[s][i]))) ){
			mp[s][i] -= tmp;
			mp[i][s] += tmp;
			return tmp;
		}
	}
	return 0;
}
int main(){
	int x,y;
	cin>>m>>n;//前者表示外籍,后者皇家
	tot = m+n+1;
	memset(mp,-1,sizeof(mp));
	memset(dis,-1,sizeof(dis));
	while(cin>>x>>y){ //前者外籍,后者皇家 
		if(x == -1) break;
		mp[x][y] = 1;
		mp[y][x] = 0;
		mp[0][x] = 1;  //起点出发
		mp[y][tot] = 1;//到终点
	}
	while(bfs()){
		int s = dfs(0,INF);
		sum+=s;
	}
	cout<<sum<<endl;
	for(int i=1;i<=m;i++){
		for(int j=m+1;j<=tot;j++){
			if(mp[i][j] == 0) cout<<i<<" "<<j<<endl;
		}
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/lala__lailai/article/details/81203640