[日常摸魚]bzoj1001狼抓兔子-最大流最小割
阿新 • • 發佈:2018-02-07
百萬 reg ret 最短 fin 網絡圖 通過 聯通 gpo
題意就是求最小割…
然後我們有這麽一個定理(最大流-最小割定理 ):
任何一個網絡圖的最小割中邊的容量之和等於圖的最大流。
(下面直接簡稱為最大流和最小割)
證明:
如果最大流>最小割,那把這些割邊刪去之後依然能找到一條增廣路使得源點和匯點聯通,和這些邊是最小割矛盾。故最大流$\leq$最小割。
而如果最大流<最小割,可是這樣通過這些割邊還能有更大的流,和最大流矛盾。
綜上,最大流=最小割~
然後看看這道題…哇$n\leq 1000$,百萬個點百萬條邊…好吧Dinic其實跑得過…而且還蠻快的…
(我懷疑正解應該是平面圖最小割轉對偶圖最短路?畢竟dinic的理論復雜度好像不太行…)
#include<cstdio> #definerep(i,a) for(register int i=1;i<=a;++i) #define debug(x) printf("%s = %d ",#x,x) const int N=1000005; const int M=1000005; const int INF=(~0u>>1); struct edge { int to,nxt,w; edge(int to=0,int nxt=0,int w=0):to(to),nxt(nxt),w(w){} }edges[N*10]; int n,m,cnt,st,ed,s,t,ans; int head[N*10],d[N],q[N]; inlineint min(int a,int b){return a<b?a:b;} inline void addEdge(int u,int v,int w) { edges[++cnt]=edge(v,head[u],w);head[u]=cnt; edges[++cnt]=edge(u,head[v],w);head[v]=cnt; } #define cur edges[i].to inline bool bfs() { rep(i,t)d[i]=0;d[s]=1; st=ed=0;q[st++]=s; while(ed<st) {int k=q[ed++]; for(register int i=head[k];i;i=edges[i].nxt)if(edges[i].w&&!d[cur]) { d[cur]=d[k]+1;q[st++]=cur; if(cur==t)return 1; } } return 0; } inline int dinic(int x,int f) { if(x==t)return f; int res=f; for(register int i=head[x];i&&res;i=edges[i].nxt)if(edges[i].w&&d[cur]==d[x]+1) { int k=dinic(cur,min(res,edges[i].w)); if(!k)d[cur]=0; edges[i].w-=k;edges[i^1].w+=k;res-=k; } return f-res; } #undef cur inline int get_num(int i,int j) { return (i-1)*m+j; } int main() { scanf("%d%d",&n,&m);cnt=1;s=get_num(1,1);t=get_num(n,m); int x; rep(i,n)rep(j,m-1){scanf("%d",&x);addEdge(get_num(i,j),get_num(i,j+1),x);} rep(i,n-1)rep(j,m){scanf("%d",&x);addEdge(get_num(i,j),get_num(i+1,j),x);} rep(i,n-1)rep(j,m-1){scanf("%d",&x);addEdge(get_num(i,j),get_num(i+1,j+1),x);} int flow; while(bfs())while((flow=dinic(s,INF)))ans+=flow; printf("%d",ans); return 0; }
[日常摸魚]bzoj1001狼抓兔子-最大流最小割