【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;
}
时间: 2024-08-28 16:10:38

【BZOJ4519】[Cqoi2016]不同的最小割 最小割树的相关文章

scu - 3254 - Rain and Fgj(最小点权割)

题意:N个点.M条边(2 <= N <= 1000 , 0 <= M <= 10^5),每一个点有个权值W(0 <= W <= 10^5),现要去除一些点(不能去掉点0),使得结点 0 与结点 N - 1 不连通,求去掉的点的最小权值和. 题目链接:http://cstest.scu.edu.cn/soj/problem.action?id=3254 -->>这是很明显的最小点权割.. 建图方案: 1)将全部点 i 拆成 i 和 i + N.i ->

3532: [Sdoi2014]Lis 最小字典序最小割

3532: [Sdoi2014]Lis Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 865  Solved: 311[Submit][Status][Discuss] Description 给定序列A,序列中的每一项Ai有删除代价Bi和附加属性Ci.请删除若干项,使得4的最长上升子序列长度减少至少1,且付出的代价之和最小,并输出方案.如果有多种方案,请输出将删去项的附加属性排序之后,字典序最小的一种. 这题难点在如何求一组最小字典序最小的最小

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

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

关于最小代价子母树

第一次尝试写动态规划(Dynamic Planning)= 问题如下: ------------------------------------------------------------------------------------------------------------------------- 最小代价子母树 设有一排数,共n个,例如:22 14 7 13 26 15 11.任意2个相邻的数可以进行归并,归并的代价为该两个数的和,经过不断的归并,最后归为一堆,而全部归并代价的

poj 3522 Slim Span 最大边减最小边最小的生成树

枚举最小边进行kruskal. #include <cstdio> #include <algorithm> using namespace std; #define maxn 120 #define maxm 10000 struct edge { int u,v,w; }e[maxm]; int p[maxn],n,m; int find(int x) { if(x==p[x]) return x; return p[x]=find(p[x]); } void link(int

BZOJ4519: [Cqoi2016]不同的最小割

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

【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

poj 3308 Paratroopers 最小割 最小点权覆盖

题目链接:http://poj.org/problem?id=3308 题意: 有一个M*N的图,上面的一些点上有伞兵. 可以设置一些枪在每行或者每列上,通过射击,这行或这列的伞兵就会被消灭.每个枪的设置有一个花费,如果设置多个枪,那么花费是设置每个枪的乘积. 问消灭所有伞兵最少的花费是多少. 思路: 每个点的伞兵至少要用那一列或者那一行设置的枪去消灭,那么就可以应用点覆盖的模型.把伞兵看成是一条边,这条边至少要用一个点来覆盖. 而题目中最终花费是所有花费的乘积,那么可以用对数log(x)+lo

UVALive 5905 Pool Construction 最小割,s-t割性质 难度:3

https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=3916 这道题要求一种填充+挖坑+建屏障的方法,使得这块土地上的所有坑和草地之间都有屏障,挖坑花费d每块,填充花费f每块,建屏障花费b每两块之间,注意并不要求一定有坑,但是外围一圈要一定没有坑,所以需要预先填充好 令st代表平地,ed代表坑,边权为花费,那么本题是要求一个st-