BZOJ 2561 最小生成树 【最大流】
Description
给定一个边带正权的连通无向图G=(V,E),其中N=|V|,M=|E|,N个点从1到N依次编号,给定三个正整数u,v,和L (u≠v),假设现在加入一条边权为L的边(u,v),那么需要删掉最少多少条边,才能够使得这条边既可能出现在最小生成树上,也可能出现在最大生成树上?
Solution
题意:在一个图中,问一条边即在最小生成树上,又在最大生成树上需要从图上删掉多少条边
在最小生成树上,一条边不被选择的充要条件是什么呢?
当比它小的边已经将它所连接的两点连接起来的时候,这条边就不能被选了
最大生成树同样
那么,先只考虑最小生成树的情况
如果这条边不在最小生成树中,边权比它小的边一定联通了这条边所接的节点u和v
我们想要花尽量少的代价使u,v不再联通
显然问题转化为了最小割
对最小生成树做一次再对最大生成树做一次,答案加起来就可以了
1 #include<bits/stdc++.h> 2 3 #define maxn 20000+5 4 #define maxm 600000+5 5 #define set(a,b) memset(a,(b),sizeof(a)) 6 #define fr(i,a,b) for(ll i=(a),_end_=(b);i<=_end_;i++) 7 #define rf(i,b,a) for(ll i=(a),_end_=(b);i>=_end_;i--) 8 #define fe(i,a,b) for(int i=first[(b)],_end_=(a);i!=_end_;i=s[i].next) 9 #define fec(i,a,b) for(int &i=cur[(b)],_end_=(a);i!=_end_;i=s[i].next) 10 11 using namespace std; 12 13 typedef long long ll; 14 15 struct sides{ 16 int u,v,c; 17 int next; 18 }s[maxm]; 19 20 struct edge{ 21 int u,v,w; 22 friend bool operator < (edge a,edge b){ 23 return a.w<b.w; 24 } 25 }e[maxm]; 26 27 queue<int> q; 28 int h[maxn],first[maxn],cur[maxn]; 29 int ind=0; 30 int cost=0; 31 int n,m,sp,tp,p; 32 33 bool comp(edge a,edge b) 34 { 35 return a.w<b.w; 36 } 37 38 void add(int u,int v,int c) 39 { 40 s[ind].u=u,s[ind].v=v,s[ind].c=c; 41 s[ind].next=first[u],first[u]=ind; 42 ind++; 43 44 s[ind].u=v,s[ind].v=u,s[ind].c=c; 45 s[ind].next=first[v],first[v]=ind; 46 ind++; 47 } 48 49 bool bfs() 50 { 51 set(h,-1); 52 h[sp]=0; 53 q.push(sp); 54 while( !q.empty() ){ 55 int sd=q.front();q.pop(); 56 fe(i,-1,sd) 57 if( h[s[i].v]==-1 && s[i].c ){ 58 h[s[i].v]=h[sd]+1; 59 q.push(s[i].v); 60 } 61 } 62 return h[tp]!=-1; 63 } 64 65 int dfs(int sd,int flow) 66 { 67 if( sd==tp ) return flow; 68 int w,used=0; 69 fec(i,-1,sd) 70 if( h[s[i].v]==h[sd]+1 && s[i].c ){ 71 w=dfs(s[i].v,min(flow-used,s[i].c)); 72 s[i].c-=w,s[i^1].c+=w; 73 used+=w; 74 if( used==flow ) return flow; 75 } 76 if( !used ) h[sd]=1; 77 return used; 78 } 79 80 void dinic() 81 { 82 while( bfs() ){ 83 fr(i,0,n+1) 84 cur[i]=first[i]; 85 cost+=dfs(sp,INT_MAX); 86 } 87 } 88 89 void solve() 90 { 91 ind=0; 92 set(first,-1); 93 fr(i,1,m) 94 if( e[i].w<p ) 95 add(e[i].u,e[i].v,1); 96 else break; 97 dinic(); 98 99 ind=0; 100 set(first,-1); 101 rf(i,1,m) 102 if( e[i].w>p ) 103 add(e[i].u,e[i].v,1); 104 else break; 105 dinic(); 106 } 107 108 int main() 109 { 110 #ifndef ONLINE_JUDGE 111 freopen("2561.in","r",stdin); 112 freopen("2561.out","w",stdout); 113 #endif 114 cin >> n >> m ; 115 fr(i,1,m) 116 cin >> e[i].u >> e[i].v >> e[i].w ; 117 sort(e+1,e+m+1,comp); 118 cin >> sp >> tp >> p ; 119 solve(); 120 cout << cost ; 121 return 0; 122 }