洛谷 P2756 飞行员配对方案问题(最大流求二分图最大匹配)

最大流求二分图最大匹配
本题要点:
1、二分图模型,转换为最大流模型
增加一个源点s和汇点t, 源点s和n个左部节点连线,边的容量是1,
m个右部节点和汇点t连线, 边的容量是1。
然后求该网络图从s到t的最大流,就是原图的二分图最大匹配
2、这里要求输出这 k 对的最大匹配。
用数组 ans存放,ans[i] 表示点i的下一个节点是哪个节点。
在update函数里,更新 ans 数组即可。

#include <cstdio>
#include <cstring>
#include <queue>
#include <iostream>
using namespace std;
const int MaxN = 210, MaxM = 11000;
const int inf = 1 << 29;
int head[MaxN], ver[MaxM], edge[MaxM], Next[MaxM], vis[MaxN];
int incf[MaxN], pre[MaxN], ans[MaxN];
int m, n, s, t, tot, maxflow;

void add(int x, int y, int z)
{
	ver[++tot] = y, edge[tot] = z, Next[tot] = head[x], head[x] = tot;
	ver[++tot] = x, edge[tot] = 0, Next[tot] = head[y], head[y] = tot;
}

bool bfs()
{
	memset(vis, 0, sizeof vis);
	queue<int> q;
	q.push(s);
	vis[s] = 1;
	incf[s] = inf;
	while(q.size())
	{
		int x = q.front(); q.pop();
		for(int i = head[x]; i; i = Next[i])
		{
			if(edge[i])
			{
				int y = ver[i];
				if(vis[y])	continue;
				incf[y] = min(incf[x], edge[i]);
				pre[y] = i;	//记录前驱
				q.push(y), vis[y] = 1;
				if(y == t)
					return true;
			}
		}
	}
	return false;
}

void update()
{
	int x = t;
	while(x != s)
	{
		int i = pre[x];
		ans[ver[i ^ 1]] = x;
		edge[i] -= incf[t];
		edge[i ^ 1] += incf[t];
		x = ver[i ^ 1];
	}
	maxflow += incf[t];
}

int main()
{
	scanf("%d%d", &m, &n);
	tot = 1, s = 0, t = n + 1;;
	for(int i = 1; i <= m; ++i)	//起点 s 连上 m个左部节点
	{
		add(0, i, 1);
	}
	for(int i = m + 1; i <= n; ++i)	// n - m 个右部节点连上 汇点t
	{
		add(i, n + 1, 1);
	}
	int x, y;
	while(scanf("%d%d", &x, &y) != EOF)
	{
		if(-1 == x && -1 == y)
			break;
		add(x, y, 1);
	}
	while(bfs())
	{
		update();
	}
	printf("%d\n", maxflow);
	for(int i = 1; i <= m; ++i)
	{
//		printf("ans[%d] = %d\n", i, ans[i]);
		if(ans[i])
		{
			printf("%d %d\n", i, ans[i]);	
		}
	}
	return 0;
}

/*
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
*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值