最小割树

本文介绍了最小割树算法,这是一种用于快速求无向图上任意两点间最小割的方法。算法通过递归构建树并利用最小割最大流定理,时间复杂度虽然理论上为O(n^3m),但在实际应用中表现高效。文章还讨论了算法的正确性证明及在不同数据规模下的运行效率,并提供了洛谷模板题的代码示例。

算法

最小割树是一个用于快速求无向图上任意两点间最小割的算法,它的定义如下:

称树 T T T 为 无向图 G G G 的最小割树,当且仅当 T T T 的节点与 G G G 一一对应,且对于所有边 ( u , v ) ∈ T (u,v) \in T (u,v)T,其边权为原图中 u , v u,v u,v 两点间最小割,同时满足在 T T T 中去掉这条边后剩下的两个不连通点集恰好为原图中 u , v u,v u,v 的最小割将原图分为的两个点集。

显然,我们可以直接根据定义递归建树,并利用最小割最大流定理每次跑一边网络流,代码:

void build(int l,int r){
   
   //node[l]到node[r]为当前要处理的连通点集
	if(l == r) return;
	int u = node[l],v = node[l + 1];//任选两点
	add(u,v,Max_Flow:: Dinic(u,v));
	int t1 = l - 1,t2 = r + 1;
	for(int i = l; i <= r; i ++){
   
   
		if(Max_Flow:: d[node[i]] == -1) t[--t2] = node[i];
		else t[++t1] = node[i];
		//d为Dinic的bfs中的到达数组,显然此时d中存的是最后一次bfs时的残量网络的连通情况
		//因为现在残量网络上s到达不了t,所以bfs访问到的点就是s所在的点集,它们的d不为0
	}
	for(int i = l; i <= r; i ++) node[i] = t[i];
	build(l,t1),build(t2,r);//node[l]到node[t1]为u所在点集,node[t2]~node[r]为v所在点集
}

那建出树后怎么查询呢?最小割树有一个重要的性质:

对于原图中任意两点 u , v u,v u,v,其最小割等于树上两点路径上边权的最小值

所以直接倍增维护就可以了。

证明

其正确性证明可以去看这篇博客,写的很严谨。

关于时间复杂度

严格来说,其时间复杂度上界约为 O ( n 3 m ) \Omicron(n^3m) O(n3m)(共跑 n − 1 n -1 n1 次最大流)。

但众所周知,网络流尤其是 Dinic / ISAP 的时间复杂度几乎不可能被卡满,更别说是在同一图中每次随机选两个点了,所以这个算法实际上跑的飞快。在 n ⩽ 850 , m ⩽ 8500 n\leqslant850,m\leqslant8500 n850,m

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值