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

最小割树

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

分治建立:

  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);
}

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

时间: 2024-10-12 14:41:38

最小割树 - CQOI2016不同的最小割的相关文章

[bzoj2229][Zjoi2011]最小割_网络流_最小割树

最小割 bzoj-2229 Zjoi-2011 题目大意:题目链接. 注释:略. 想法: 在这里给出最小割树的定义. 最小割树啊,就是这样一棵树.一个图的最小割树满足这棵树上任意两点之间的最小值就是原图中这两点之间的最小割. 这个性质显然是非常优秀的. 我们不妨这样假设,我么已经把最小割树求出来了,那么这个题就迎刃而解了. 我们可以直接枚举点对,然后暴力验证就可以直接枚举出所有的合法点对是吧. 那么问题来了,我们如何才能求出所有的合法的点对? 这就需要用到了最小割树的构建过程. 我们最小割树的构

【BZOJ4519】[Cqoi2016]不同的最小割 最小割树

[BZOJ4519][Cqoi2016]不同的最小割 Description 学过图论的同学都知道最小割的概念:对于一个图,某个对图中结点的划分将图中所有结点分成两个部分,如果结点s,t不在同一个部分中,则称这个划分是关于s,t的割.对于带权图来说,将所有顶点处在不同部分的边的权值相加所得到的值定义为这个割的容量,而s,t的最小割指的是在关于s,t的割中容量最小的割.而对冲刺NOI竞赛的选手而言,求带权图中两点的最小割已经不是什么难事了.我们可以把视野放宽,考虑有N个点的无向连通图中所有点对的最

BZOJ4519: [Cqoi2016]不同的最小割

Description 学过图论的同学都知道最小割的概念:对于一个图,某个对图中结点的划分将图中所有结点分成 两个部分,如果结点s,t不在同一个部分中,则称这个划分是关于s,t的割.对于带权图来说,将 所有顶点处在不同部分的边的权值相加所得到的值定义为这个割的容量,而s,t的最小割指的是在 关于s,t的割中容量最小的割. 而对冲刺NOI竞赛的选手而言,求带权图中两点的最小割已经不是什么难事了.我们可以把 视野放宽,考虑有N个点的无向连通图中所有点对的最小割的容量,共能得到N(N−1) 2个数值.

【BZOJ-2229】最小割 最小割树(最大流+分治)

2229: [Zjoi2011]最小割 Time Limit: 10 Sec  Memory Limit: 259 MBSubmit: 1565  Solved: 560[Submit][Status][Discuss] Description 小白在图论课上学到了一个新的概念——最小割,下课后小白在笔记本上写下了如下这段话: “对于一个图,某个对图中结点的划分将图中所有结点分成两个部分,如果结点s,t不在同一个部分中,则称这个划分是关于s,t的割. 对于带权图来说,将所有顶点处在不同部分的边的

【BZOJ-4519】不同的最小割 最小割树(分治+最小割)

4519: [Cqoi2016]不同的最小割 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 393  Solved: 239[Submit][Status][Discuss] Description 学过图论的同学都知道最小割的概念:对于一个图,某个对图中结点的划分将图中所有结点分成 两个部分,如果结点s,t不在同一个部分中,则称这个划分是关于s,t的割.对于带权图来说,将 所有顶点处在不同部分的边的权值相加所得到的值定义为这个割的容量,而s,t

【BZOJ-4435】Juice Junctions 最小割树(分治+最小割)+Hash

4435: [Cerc2015]Juice Junctions Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 20  Solved: 11[Submit][Status][Discuss] Description 你被雇佣升级一个旧果汁加工厂的橙汁运输系统.系统有管道和节点构成.每条管道都是双向的,且每条管道的流量都是1升每秒.管道可能连接节点,每个节点最多可以连接3条管道.节点的流量是无限的.节点用整数1到n来表示.在升级系统之前,你需要对现有

bzoj2229: [Zjoi2011]最小割(分治最小割+最小割树思想)

2229: [Zjoi2011]最小割 题目:传送门 题解: 一道非常好的题目啊!!! 蒟蒻的想法:暴力枚举点对跑最小割记录...绝对爆炸啊.... 开始怀疑是不是题目骗人...难道根本不用网络流???一看路牌....分治最小割?最小割树? 然后开始各种%论文... 简单来说吧,根据各种本蒟蒻不会证明的理论,那么:所有最小割都不是完全独立的,总共有n-1种(也就是树上的n-1条边)最小割 恰好和树的定义一样啊! 那么用一个solve递归函数来解决,一开始任意找两个点作为st和ed来最小割,然后分

bzoj2229: [Zjoi2011]最小割(最小割树)

传送门 这题是用最小割树做的(不明白最小割树是什么的可以去看看这一题->这里) 有了最小割树就很简单了……点数那么少……每次跑出一个最大流就暴力搞一遍就好了 1 //minamoto 2 #include<iostream> 3 #include<cstdio> 4 #include<cstring> 5 #include<algorithm> 6 #include<queue> 7 #define inf 0x3f3f3f3f 8 usi

网络战争 [KD-Tree+最小割树]

题面 思路 首先吐槽一下: 这题是什么东西啊??出题人啊,故意拼题很有意思吗??还拼两个这么毒瘤的东西???? 10K代码了解一下???? 然后是正经东西 首先,本题可以理解为这样: 给定$n$个块,每个块有一个根,每个根只会主动连出去一条无向边,每次求两点最小割 那么,我们显然可以把每个块内的最小割树建立出来,同时把块的根之间的最小割树也建立出来 如果询问点在同一个块里面,显然可以直接最小割树处理 否则就是两边的点到块根的最小割和两个块根之间的最小割的最小值 所以,我们先对于所有的块根,建出K