[BZOJ4519] 不同的最小割 - 分治,最小割(Gomory-Hu Tree)

题目大意:求一张图的不同的最小割个数。

这里我们用Gomory-Hu Tree的思想但却并不需要建立那样的一棵最小割树。首先我们要知道最小割不会相互跨立(ZZT不会证233),然后就可以每次随机选取两点,求出最小割后分治两边的点集即可,根据最大流最小割定理,直接跑一遍dinic就可以了。时间复杂度上界O(n^2mlog n),实际复杂度完全可以接受。

upd.如果两个最小割会相互跨立,那么显然这两个最小割要重合(否则可以通过改变其中一个割切使割更小),所以就显然了qwq

#include"bits/stdc++.h"
using namespace std;

#define gch getchar()
template
void read(integer&x){
	x=0;int f=1;char ch=gch;
	while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=gch;}
	while(ch<='9'&&ch>='0'){x=x*10+ch-'0';ch=gch;}
	x*=f;
}

const int inf=(int)1e9;
const int N=855,M=8505;

set ans;
struct Edge{
	int to,flow;
	Edge (int _=0,int __=0)
	{ to=_; flow=__;}
} e[M<<1];
int h[N],nxt[M<<1],n,m;
int S,T,d[N],q[N],l,r,cnt=1;

bool bfs(){
	memset(d,-1,sizeof(d));
	l=0,r=1;q[1]=S;d[S]=0;
	while(l>1;
}

int di[N],color[N];

void paint(int fr){
	color[fr]=1;
	for(int i=h[fr];i;i=nxt[i]){
		if(e[i].flow&&color[e[i].to]^1){
			paint(e[i].to);
		}
	}
}

void solve(int l,int r){
	if(l==r)return;
	reset();S=di[l],T=di[r];
	int mincut=dinic(),i,j;
	if(ans.find(mincut)==ans.end())
		ans.insert(mincut);
	memset(color,0,sizeof(color));
	paint(di[l]);
	for(i=j=l;i<=r;i++){
		while(color[di[j]])j++;
		if(color[di[i]]&&i>j)
			swap(di[i],di[j++]);
	}
	solve(l,j-1);solve(j,r);
}

inline void add(int u,int v,int f){e[++cnt]=Edge(v,f),nxt[cnt]=h[u],h[u]=cnt;}

void init(){
	read(n),read(m);
	int i,u,v,flow;
	for(i=1;i<=m;i++){
		read(u),read(v),read(flow);
		add(u,v,flow);add(v,u,flow);
	}
}

int main(){
	init();for(int i=1;i<=n;i++)di[i]=i;
	std:: random_shuffle(di+1,di+n+1);
	solve(1,n);printf("%d\n",ans.size());
	return 0;
}


你可能感兴趣的:(线性规划,数据结构)