bzoj 2561: 最小生成树

2561: 最小生成树

Description

 给定一个边带正权的连通无向图G=(V,E),其中N=|V|,M=|E|,N个点从1到N依次编号,给定三个正整数u,v,和L (u≠v),假设现在加入一条边权为L的边(u,v),那么需要删掉最少多少条边,才能够使得这条边既可能出现在最小生成树上,也可能出现在最大生成树上?

Input

  第一行包含用空格隔开的两个整数,分别为N和M;
  接下来M行,每行包含三个正整数u,v和w表示图G存在一条边权为w的边(u,v)。
  最后一行包含用空格隔开的三个整数,分别为u,v,和 L;
  数据保证图中没有自环。
 

Output

 输出一行一个整数表示最少需要删掉的边的数量。

Sample Input

3 2
3 2 1
1 2 3
1 2 2

Sample Output

1

HINT

对于20%的数据满足N ≤ 10,M ≤ 20,L ≤ 20;
对于50%的数据满足N ≤ 300,M ≤ 3000,L ≤ 200;
对于100%的数据满足N ≤ 20000,M ≤ 200000,L ≤ 20000。

Source

2012国家集训队Round 1 day1

题解:

很神 的做法,居然是网络流。。。%%%%%

不过知道具体是最小割也就不觉得奇怪了。

对于u,v如果它是最大生成树的一条边,那么对于所有权大于L的边构成的图,无法使u和v联通。。。

最小代价也就是最小割。。注意新加的边可能本来就有,所以RT应该是严格大于。

对于小于的也在求一遍

#include<stdio.h>
#include<iostream>
using namespace std;
const int N=20005;
const int M=200005;
int n,m,i,w,k,src,tar,ans,a[M],b[M],c[M],p[N],dis[N],gap[N];
int tot,head[N],Next[M<<1],to[M<<1],v[M<<1];
inline void read(int &v){ 
    char ch,fu=0;
    for(ch='*'; (ch<'0'||ch>'9')&&ch!='-'; ch=getchar());
    if(ch=='-') fu=1, ch=getchar();
    for(v=0; ch>='0'&&ch<='9'; ch=getchar()) v=v*10+ch-'0';
    if(fu) v=-v;
}
void add(int x,int y,int z)
{
	to[tot]=y;
	v[tot]=z;
	Next[tot]=head[x];
	head[x]=tot++;
}
int isap(int x,int s)
{
	if(x==tar) return s;
	int flow=0,Min=n-1,i;
	for(i=head[x];i!=-1;i=Next[i])
	{
		int y=to[i];
		if(v[i]>0)
		{
			if(dis[x]==dis[y]+1)
			{
				int tmp=isap(y,min(s-flow,v[i]));
				flow+=tmp;
				v[i]-=tmp;
				v[i^1]+=tmp;
			}
			Min=min(Min,dis[y]);
		}
		if(flow==s) return flow;
		if(dis[src]==n) return flow;
	}
	if(flow==0)
	{
		gap[dis[x]]--;
		if(gap[dis[x]]==0) dis[src]=n;
		dis[x]=Min+1;
		gap[dis[x]]++;
	}
	return flow;
}
int main()
{
	read(n),read(m);
	for(i=1;i<=n;i++) head[i]=-1;
	for(i=1;i<=m;i++)
		read(a[i]),read(b[i]),read(c[i]);
	read(src),read(tar),read(w);
	p[src]=p[tar]=1;
	for(i=1;i<=m;i++)
	    if(c[i]>w) add(a[i],b[i],1),add(b[i],a[i],1),p[a[i]]=p[b[i]]=1;
	for(i=1;i<=n;i++) k+=p[i];
	n=k;
	gap[0]=n;
	while(dis[src]<n) ans+=isap(src,1e9);
	tot=0;k=0;
	for(i=1;i<=n;i++) head[i]=-1,dis[i]=p[i]=gap[i]=0;
	p[src]=p[tar]=1;
	for(i=1;i<=m;i++)
	    if(c[i]<w) add(a[i],b[i],1),add(b[i],a[i],1),p[a[i]]=p[b[i]]=1;
	for(i=1;i<=n;i++) k+=p[i];
	n=k;
	gap[0]=n;
	while(dis[src]<n) ans+=isap(src,1e9); 
	cout<<ans;
	return 0;
} 

  

posted @ 2016-07-27 18:54  lwq12138  阅读(176)  评论(0编辑  收藏  举报