[CQOI2016]不同的最小割 分治最小割

[CQOI2016]

  • 求一个无向图中所有点对之间的本质不同的最小割的个数
  • 一张图最多有n-1种本质不同的最小割,考虑如何快速地找到所有不同的最小割
  • 只要让每次划分的S,T集合存在区别,就对应了不同的最小割
  • 我们考虑分治来解决这问题,首先对于我们当前分治的点集,我们任选 两个点 s,t,然后我们计算这两个点之间的最小割,这个时候整张图会 被我们划分为 S,T 两个点集
  • 这个时候当前对于当前点集划分的两个集合,我们对这两个集合递归的执行刚才的步骤,这个时候我们保证新的 S,T 所划分出的集合一定和原 来的集合不同,也就对应了不同的最小割
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define per(i,a,b) for(int i=(a);i>=(b);i--)
using namespace std;
const int inf=1e9;
const int N=1e3;
const int M=1e4;
struct node{int y,n,v;}e[M<<1];
int lin[M<<1],tmp[N],v[N],a[N],d[N],maxflow,len=1,S,T,n,m,x,y,w;
set<int> s; 
inline int read(){
	int num=0;char ch=getchar();
	while(!isdigit(ch))ch=getchar();
	while(isdigit(ch))num=num*10+ch-'0',ch=getchar();
	return num;
}
inline void Print(int x){if(x>9)Print(x/10);putchar(x%10+'0');}

void LK(int x,int y,int v){
	e[++len].y=y,e[len].v=v,e[len].n=lin[x],lin[x]=len;
}
void add(int x,int y,int v){
	LK(x,y,v),LK(y,x,v);
}
bool bfs(){
	queue<int> q;
	memset(d,0,sizeof(d));
	q.push(S),d[S]=1;
	while(q.size()){
		int x=q.front();q.pop();
		for(int i=lin[x];i;i=e[i].n){
			int y=e[i].y;
			if(!e[i].v||d[y])continue;
			d[y]=d[x]+1;
			q.push(y);
		}
	}return d[T]>0;
}
int dfs(int x,int minf){
	if(x==T)return minf;
	int flow=0,sum=0;
	for(int i=lin[x];i;i=e[i].n){
		int y=e[i].y;
		if(d[y]!=d[x]+1||!e[i].v)continue;
		flow=dfs(y,min(minf,e[i].v));
		if(!flow)d[y]=0;
		sum+=flow,minf-=flow,e[i].v-=flow,e[i^1].v+=flow;
		if(!minf)return sum;
	}return sum;
}
int dinic(int s,int t){
	S=s,T=t,maxflow=0;
	while(bfs())maxflow+=dfs(S,inf);
	return maxflow;
}
void DFS(int x){
	v[x]=1;
	for(int i=lin[x];i;i=e[i].n){
		int y=e[i].y;
		if(!e[i].v||v[y])continue;
		DFS(y);
	}
}
void reset(){
	for(int i=2;i<=len;i+=2){
		e[i].v=e[i^1].v=(e[i].v+e[i^1].v)>>1;
	}
}
void CDQ(int l,int r){
	if(l==r)return ;
	//cout<<l<<" "<<r<<"\n";
	reset();
	memset(v,0,sizeof(v));
	int ans=dinic(a[l],a[r]);
	s.insert(ans);
	DFS(a[l]);
	int L=l,R=r;
	rep(i,l,r){
		if(v[a[i]])tmp[L++]=a[i];
		else tmp[R--]=a[i];
	}
	rep(i,l,r)a[i]=tmp[i];
	CDQ(l,L-1),CDQ(R+1,r);
}
int main()
{
	//freopen("a.in","r",stdin);
	n=read(),m=read();
	rep(i,1,m){x=read(),y=read(),w=read();add(x,y,w);}
	rep(i,1,n)a[i]=i;
	CDQ(1,n);
	cout<<s.size();
	return 0;
}

猜你喜欢

转载自blog.csdn.net/strangeDDDF/article/details/88761503