首页 > 代码库 > 【BZOJ4519】[Cqoi2016]不同的最小割 最小割树

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

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

Description

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

Input

输入文件第一行包含两个数N,M,表示点数和边数。接下来M行,每行三个数u,v,w,
表示点u和点v(从1开始标号)之间有条边权值是w。
1<=N<=850 1<=M<=8500 1<=W<=100000

Output

 输出文件第一行为一个整数,表示个数。

Sample Input

4 4
1 2 3
1 3 6
2 4 5
3 4 4

Sample Output

3

题解:同BZOJ2229

 

#include <cstdio>#include <cstring>#include <iostream>#include <queue>#include <algorithm>using namespace std;int n,m,cnt,S,T,ans;int to[20000],next[20000],val[20000],head[1000],d[1000];int map[1000][1000],p[1000],pp[1000],s[1000000];queue<int> q;void add(int a,int b,int c){	to[cnt]=b,val[cnt]=c,next[cnt]=head[a],head[a]=cnt++;	to[cnt]=a,val[cnt]=c,next[cnt]=head[b],head[b]=cnt++;}int dfs(int x,int mf){	if(x==T)	return mf;	int k,temp=mf,i;	for(i=head[x];i!=-1;i=next[i])	{		if(d[to[i]]==d[x]+1&&val[i])		{			k=dfs(to[i],min(temp,val[i]));			if(!k)	d[to[i]]=0;			val[i]-=k,val[i^1]+=k,temp-=k;			if(!temp)	break;		}	}	return mf-temp;}int bfs(){	while(!q.empty())	q.pop();	memset(d,0,sizeof(d));	d[S]=1,q.push(S);	int i,u;	while(!q.empty())	{		u=q.front(),q.pop();		for(i=head[u];i!=-1;i=next[i])		{			if(!d[to[i]]&&val[i])			{				d[to[i]]=d[u]+1;				if(to[i]==T)	return 1;				q.push(to[i]);			}		}	}	return 0;}void solve(int l,int r){	if(l==r)	return ;	S=p[l],T=p[r];	int i,j,h1=l,h2=r,mf=0;	for(i=0;i<cnt;i+=2)	val[i]=val[i^1]=val[i]+val[i^1]>>1;	while(bfs())	mf+=dfs(S,1<<30);	for(i=1;i<=n;i++)	if(d[i])		for(j=1;j<=n;j++)	if(!d[j])			map[i][j]=map[j][i]=min(map[i][j],mf);	for(i=l;i<=r;i++)	{		if(d[p[i]])	pp[h1++]=p[i];		else	pp[h2--]=p[i];	}	for(i=l;i<=r;i++)	p[i]=pp[i];	solve(l,h2),solve(h1,r);}int rd(){	int ret=0,f=1;	char gc=getchar();	while(gc<‘0‘||gc>‘9‘)	{if(gc==‘-‘)f=-f;	gc=getchar();}	while(gc>=‘0‘&&gc<=‘9‘)	ret=ret*10+gc-‘0‘,gc=getchar();	return ret*f;}int main(){	n=rd(),m=rd();	int i,j,a,b,c,pre;	memset(head,-1,sizeof(head));	memset(map,0x3f,sizeof(map));	for(i=1;i<=m;i++)	a=rd(),b=rd(),c=rd(),add(a,b,c);	for(i=1;i<=n;i++)	p[i]=i;	solve(1,n);	for(i=1;i<=n;i++)	for(j=i+1;j<=n;j++)	s[++s[0]]=map[i][j];	sort(s+1,s+s[0]+1);	for(pre=-1,i=1;i<=s[0];i++)	if(s[i]>pre)	pre=s[i],ans++;	printf("%d",ans);	return 0;}

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