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;
数据保证图中没有自环。
接下来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
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
题解:
很神 的做法,居然是网络流。。。%%%%%
不过知道具体是最小割也就不觉得奇怪了。
对于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; }
一念起,天涯咫尺; 一念灭,咫尺天涯。