码迷,mamicode.com
首页 > 其他好文 > 详细

最小割树 - CQOI2016不同的最小割

时间:2020-03-25 19:36:07      阅读:58      评论:0      收藏:0      [点我收藏+]

标签:时间复杂度   最小   ref   push   时间   memcpy   dig   empty   alt   

最小割树

快速求无向图两点间的最小割

分治建立:

  1. 区间内任选两点\(x,y\),跑最小割,连边\((x,y,cut_{x,y})\)
  2. 根据此最小割,把点割成两部分,递归处理
  3. 新建出的树,两点路径上的最小值即为他们在原图上的最小割

时间复杂度\(O(n^3m)\),但网络流很难卡满

正确性证明

技术图片
\(N850M8500\)

最小割树板题

#include<bits/stdc++.h>
using namespace std;
inline int read(){
	int x=0,f=1;char c=getchar();
	while(!isdigit(c)){if(c==‘-‘)f=-1;c=getchar();}
	while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
	return f==1?x:-x;
}
const int N=852,M=17004,inf=0x3f3f3f3f;
int n,m,p[N],p1[N];
set<int>s;
inline void add(int u,int v,int w){
	s.insert(w);
}
namespace gragh{
	struct edge{
		int v,f,yf,nxt;
	}e[M];
	int first[N],cnt=1,cur[N],s,t,cn=0,vis[N],dep[N];
	inline void add(int u,int v,int w){
		e[++cnt]=(edge){v,w,w,first[u]};first[u]=cnt;
		e[++cnt]=(edge){u,w,w,first[v]};first[v]=cnt;
	}
	inline bool bfs(){
		static queue<int>q;
		while(!q.empty())q.pop();
		memset(dep,-1,sizeof(dep));
		dep[s]=1;q.push(s);
		while(!q.empty()){
			int x=q.front();q.pop();
			for(int i=first[x],v;i;i=e[i].nxt){
				v=e[i].v;
				if(e[i].f&&dep[v]==-1){
					dep[v]=dep[x]+1;
					if(v==t)return 1;
					q.push(v);
				}
			}
		} 
		return 0;
	}
	int dfs(int x,int f){
		if(x==t||!f)return f;
		int used=0;
		for(int &i=cur[x],v,w;i;i=e[i].nxt){
			v=e[i].v;
			if(!e[i].f||dep[v]!=dep[x]+1)continue;
			w=dfs(v,min(f,e[i].f));
			if(!w)continue;
			e[i].f-=w;e[i^1].f+=w;
			f-=w;used+=w;
			if(!f)break;
		}
		return used;
	}
	inline int dinic(int u,int v){
		s=u;t=v;
		for(int i=2;i<=cnt;i++)e[i].f=e[i].yf;
		int flow=0;
		while(bfs()){
			memcpy(cur,first,sizeof(first));
			flow+=dfs(s,inf);
		}
		return flow;
	}
	void dfs(int x){
		vis[x]=cn;
		for(int i=first[x],v;i;i=e[i].nxt){
			v=e[i].v;
			if(e[i].f&&vis[v]!=cn)dfs(v);
		}
	}
	void build(int l,int r){
		if(l>=r)return;
		int x=p[l],y=p[l+1],ll=l,rr=r;
		int cut=dinic(x,y);
		cn++;dfs(x);
		for(int i=l;i<=r;i++)
			if(vis[p[i]]==cn)p1[ll++]=p[i];
			else p1[rr--]=p[i];
		for(int i=l;i<=r;i++)p[i]=p1[i];
		::add(x,y,cut);
		build(l,ll-1);build(rr+1,r);
	}
}
int main(){
	n=read();m=read();
	for(int i=1,u,v,w;i<=m;i++){
		u=read();v=read();w=read();
		gragh::add(u,v,w);
	} 
	for(int i=1;i<=n;i++)p[i]=i;
	gragh::build(1,n);
	cout<<s.size(); 
	return (0-0);
}

最小割树 - CQOI2016不同的最小割

标签:时间复杂度   最小   ref   push   时间   memcpy   dig   empty   alt   

原文地址:https://www.cnblogs.com/aurora2004/p/12567811.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!