1. 程式人生 > >【BZOJ4519】[Cqoi2016]不同的最小割 最小割樹

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

main href family iostream 有趣的 rip tput ans val

【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]不同的最小割 最小割樹