最小割點【洛谷P1345】
阿新 • • 發佈:2018-11-21
傳送門:https://www.luogu.org/problemnew/show/P1345
最小割問題,大家應該聽說過,最大流最小割吧(沒聽說過的讀完這句話應該聽說了),既然要求最小割,那麼我們就直接dinic跑一下最大流就完事了。
有人要問了,你說的輕巧,我寫了dinic怎麼WA了???
這個題是最小割【點】啊!
平常的dinic跑最大流求最小割那割的是邊。
:那怎麼割點啊,看起來很困難啊好像。
觀察一下這個網路流,有1~n個點,有m條邊。
既然題目要我割點,那麼我們就把點拆成邊就好啦。
我們把點i連在i+n上,我們就把點拆成了邊,而且邊權是1,那麼這個邊割掉了,就相當於這個點割掉了。
其餘的正常的邊設定成INF吧。
下面是我優美的dinic模板,(只寫了當前弧優化,沒寫炸點優化)
PS:跑dinic的時候傳參傳了(c1,c2),WA翻天,百思不得其解,突然靈機一動,我點都拆開了,我在幹嘛???
#include <bits/stdc++.h> using namespace std; const int maxn = 1010; const int INF = 1e9+7; int n,m,c1,c2; struct edge { int to; int cap; int rev; }; vector<edge> G[maxn]; int depth[maxn],arc[maxn]; void add_edge(int from,int to,int cost) { G[from].push_back((edge){to,cost,G[to].size()}); G[to].push_back((edge){from,0,G[from].size()-1}); } void bfs(int s) { queue<int> q; memset(depth,-1,sizeof(depth)); depth[s] = 0; q.push(s); while(!q.empty()) { int v = q.front(); q.pop(); for(int i=0;i<G[v].size();i++) { edge &e = G[v][i]; if(e.cap>0 && depth[e.to]<0) { depth[e.to] = depth[v]+1; q.push(e.to); } } } } int dfs(int v,int t,int f) { if(v==t) return f; for(int &i=arc[v];i<G[v].size();i++) { edge &e = G[v][i]; if(e.cap>0 && depth[e.to]==depth[v]+1) { int d = dfs(e.to,t,min(f,e.cap)); if(d>0) { e.cap -= d; G[e.to][e.rev].cap += d; return d; } } } return 0; } int dinic(int s,int t) { int flow = 0; while(true) { bfs(s); if(depth[t]<0) return flow; memset(arc,0,sizeof(arc)); int f; while((f=dfs(s,t,INF))>0) { flow += f; } } } int main() { cin>>n>>m>>c1>>c2; for(int i=1;i<=n;i++) { add_edge(i,i+n,1); } for(int i=0;i<m;i++) { int x,y; cin>>x>>y; add_edge(x+n,y,INF); add_edge(y+n,x,INF); } cout<<dinic(c1+n,c2)<<endl; return 0; }