(GCPC 2017) F. Plug It In

https://codeforces.com/gym/101873/problem/F

题意有m个插座,有n个电器,m个插座和n个用电器之间有k条边。
插座和插座之前没有边,电器和电器之间没有边。一个插座插一个电器。
是个二分图。
现在可以选择其中1个插座使它可以插3个电器,问最多多少电器可以通上电。

这题其实就是查找二分图的最大匹配。
但存在1个插座可以插3个电器的情况,也许会容易思考到网络流,或者把1个点拆成3个点。
无论如何,跑一次二分图最大匹配的最优时间复杂度是 O ( n   m ) O(\sqrt n \ m) O(n  m),如果枚举每一个点,那么总的时间复杂度是 O ( n m n ) O(nm \sqrt n) O(nmn ) 无法通过

细思考一下二分图匹配的增广路算法,例如现在选择第 i i i个点使它变成可以插3个电器。
网络流:
从原点到第 i i i个点的流量变成3,继续在残余图上寻找增广路
匈牙利等朴素增广路算法:
“复制”第 i i i个点,使其变为 n + 1 , n + 2 n+1,n+2 n+1,n+2,然后再对这两个点找两次增广路。

从而发现网络流和匈牙利算法都可以在“每个插座匹配一个电气”的基础上继续匹配。
所以我们可以保存下插座变化前的图的匹配状态(或者网络流的流量状态,即残余图),然后添加节点(或网络流中边的流量),继续增广。
此时,每一轮重新增广,只会多寻找2次增广路,遍历全图最多两次,所以枚举每一个点时间复杂度变成 O ( m + n ) O(m+n) O(m+n)
总时间复杂度为
O ( n m ) O(nm) O(nm)
可以用网络流或者匈牙利算法实现,前者常数较大注意卡常。

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+9;
vector<int> g[maxn];
int link[maxn],save[maxn];//
char vis[maxn];
int dfs(int x){
	for(int i:g[x]){
		if(vis[i]) continue;
		vis[i]=1;
		if(link[i]==0||dfs(link[i])) 
			return link[i]=x,1;
	}
	return 0;
}
int main(){
	int n,m,k;
	scanf("%d%d%d",&n,&m,&k);
	for(int u,v,i=1;i<=k;i++){
		scanf("%d%d",&u,&v);
		g[u].push_back(v);
	}
	int base=0,ans;
	for(int i=1;i<=n;i++){
		memset(vis,0,m+3);
		ans+=dfs(i);
	}
	base=ans;
	memcpy(save,link,sizeof(int)*(m+3));//save存下图匹配的状态
	for(int i=1;i<=n;i++){
		memcpy(link,save,sizeof(int)*(m+3));//读取图改变之前的匹配状态
		memset(vis,0,m+3);
		int tv=0;
		for(int j=1;j<=2;j++) tv+=dfs(i);//这里在原来的点上增广
		ans=max(ans,base+tv);
	}
	printf("%d\n",ans);
}

图中是是用了类似匈牙利算法去跑这个匹配,可能让人寻味的即是第34行中,为什么可以在第i个点上直接继续寻找增广路。

例如对于样例1
原图跑完增广路之后的边匹配情况
原图跑完增广路之后的边匹配情况,红色为匹配边。
接下来考虑选择第i个点之后的两轮增广情况:
第一轮如何增广的:
在这里插入图片描述
第二轮如何增广的:
在这里插入图片描述
最后图的匹配情况为:
在这里插入图片描述
可以发现vis数组起了关键的作用。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值