2561: 最小生成树
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 2248 Solved: 1073
[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。
Source
首先我们要明确一个最小生成树的性质(貌似是切割性质还是啥的忘了),
那就是如果一条边在它所在的任意环里都是最小的话,那么它肯定是在最小生成树中的;反之亦然。
最大生成树的情况类似。
如果要让这条边在最小生成树中,那么它和比它小的边所构成的图中不能有环,也就是u和v除了这条直接连接的边没有路径联通。
这不就是u到v的最小割吗?
最大生成树的情况类似,而且非常好的一点是,
所有比(u,v)小的边和比(u,v)大的边是相互独立的,
这就提示我们可以单独求解,最后加起来就行了。
/************************************************************** Problem: 2561 User: JYYHH Language: C++ Result: Accepted Time:1332 ms Memory:18980 kb ****************************************************************/ #include<bits/stdc++.h> #define ll long long #define maxn 40005 #define pb push_back using namespace std; const int inf=1<<29; vector<int> g[maxn]; struct lines{ int to,flow,cap; }l[maxn*20]; int t=-1,S,T,n; int d[maxn],cur[maxn]; bool v[maxn]; inline void add(int xx,int yy,int zz){ l[++t]=(lines){yy,0,zz},g[xx].pb(t); l[++t]=(lines){xx,0,0},g[yy].pb(t); } inline bool bfs(){ queue<int> q; memset(v,0,sizeof(v)); d[S]=0,v[S]=1,q.push(S); int x; lines e; while(!q.empty()){ x=q.front(),q.pop(); for(int i=g[x].size()-1;i>=0;i--){ e=l[g[x][i]]; if(!v[e.to]&&e.flow<e.cap){ d[e.to]=d[x]+1; v[e.to]=1; q.push(e.to); } } } return v[T]; } int dfs(int x,int a){ if(x==T||!a) return a; int flow=0,f,sz=g[x].size(); for(int &i=cur[x];i<sz;i++){ lines &e=l[g[x][i]]; if(d[x]==d[e.to]-1&&(f=dfs(e.to,min(a,e.cap-e.flow)))){ flow+=f,a-=f; e.flow+=f,l[g[x][i]^1].flow-=f; if(!a) break; } } return flow; } inline int max_flow(){ int an=0; while(bfs()){ memset(cur,0,sizeof(cur)); an+=dfs(S,inf); } return an; } inline void init(){ for(int i=1;i<=n;i++) g[i].clear(); t=-1; } int m,W,ww[maxn*5]; int uu[maxn*5],vv[maxn*5]; int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=m;i++){ scanf("%d%d%d",uu+i,vv+i,ww+i); } scanf("%d%d%d",&S,&T,&W); int ans=0; for(int i=1;i<=m;i++) if(ww[i]<W){ add(uu[i],vv[i],1); add(vv[i],uu[i],1); } ans+=max_flow(); init(); for(int i=1;i<=m;i++) if(ww[i]>W){ add(uu[i],vv[i],1); add(vv[i],uu[i],1); } ans+=max_flow(); printf("%d\n",ans); return 0; }