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 }

 

posted @ 2015-07-03 13:12  ST_Saint  阅读(403)  评论(0编辑  收藏  举报