bzoj2561: 最小生成树
如果出现在最小生成树上,那么此时比该边权值小的边无法连通uv。据此跑最小割(最大流)即可。
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; #define rep(i,n) for(int i=1;i<=n;i++) #define clr(x,c) memset(x,c,sizeof(x)) int read(){ int x=0;char c=getchar();bool f=true; while(!isdigit(c)) { if(c=='-') f=false;c=getchar(); } while(isdigit(c)) x=x*10+c-'0',c=getchar(); return f?x:-x; } const int nmax=20005; const int maxn=200005; const int inf=0x7f7f7f7f; struct Edge{ int from,to,cap; bool operator<(const Edge&rhs)const{ return cap<rhs.cap;} }; Edge Edges[maxn]; struct edge{ int to,cap;edge *next,*rev; }; edge edges[maxn<<2],*pt,*head[nmax],*p[nmax],*cur[nmax]; void add(int u,int v,int d){ pt->to=v;pt->cap=d;pt->next=head[u];head[u]=pt++; } void adde(int u,int v,int d){ add(u,v,d);add(v,u,0);head[u]->rev=head[v];head[v]->rev=head[u]; } int cnt[nmax],h[nmax]; int maxflow(int s,int t,int n){ clr(cnt,0);clr(h,0);cnt[0]=n; int flow=0,a=inf,x=s;edge *e; while(h[s]<n){ for(e=cur[x];e;e=e->next) if(e->cap>0&&h[e->to]+1==h[x]) break; if(e){ p[e->to]=cur[x]=e;a=min(a,e->cap);x=e->to; if(x==t){ while(x!=s) p[x]->rev->cap+=a,p[x]->cap-=a,x=p[x]->rev->to; flow+=a,a=inf; } }else{ if(!--cnt[h[x]]) break; h[x]=n; for(e=head[x];e;e=e->next) if(e->cap>0&&h[e->to]+1<h[x]) h[x]=h[e->to]+1,cur[x]=e; cnt[h[x]]++; if(x!=s) x=p[x]->rev->to; } } return flow; } int main(){ int n=read(),m=read(),s,t,d; rep(i,m) Edges[i].from=read(),Edges[i].to=read(),Edges[i].cap=read(); s=read(),t=read(),d=read(); sort(Edges+1,Edges+m+1); // rep(i,m) printf("%d %d %d\n",Edges[i].from,Edges[i].to,Edges[i].cap); pt=edges;clr(head,0); rep(i,m){ if(Edges[i].cap>=d) break; Edge&o=Edges[i];adde(o.from,o.to,1);adde(o.to,o.from,1); } int ans=maxflow(s,t,n); pt=edges;clr(head,0); for(int i=m;i;i--){ if(Edges[i].cap<=d) break; Edge&o=Edges[i];adde(o.from,o.to,1);adde(o.to,o.from,1); } ans+=maxflow(s,t,n); printf("%d\n",ans); return 0; }
2561: 最小生成树
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1459 Solved: 716
[Submit][Status][Discuss]
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。