標籤:
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_JUDGE111 freopen("2561.in","r",stdin);112 freopen("2561.out","w",stdout);113 #endif114 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 }
BZOJ 2561 最小產生樹 【最大流】