您的位置:首页 > 其它

bzoj 2561: 最小生成树

2016-07-27 18:54 204 查看

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
,dis
,gap
;
int tot,head
,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;
}


  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: