《網 絡 瘤:從入門到入土》第一卷
阿新 • • 發佈:2021-11-14
網路流學習筆記第一篇(
\[\huge\color{cornflowerblue}{\texttt{Net flow studying notes: NO.1.}}
\]\[\large\color{gold}{\texttt{Only Templates Here.}}
\]
\[\texttt{updated on 2021.10.31:} \]\[\texttt{我透 剛才都沒發現我SSP的當前弧優化加到狗身上去了(((} \]\[\texttt{加了快150ms} \]
\[\color{skyblue}{\texttt{And We,}} \]\[\color{skyblue}{\texttt{We Burn Faster Than Lights,}} \]\[\color{skyblue}{\texttt{Shine Across In The Night Sky,}} \]\[\color{skyblue}{\texttt{We Burn Faster Than Lights.}} \]\[\color{gold}{◢_◤} \]
\[\texttt{updated on 2021.10.31:} \]\[\texttt{我透 剛才都沒發現我SSP的當前弧優化加到狗身上去了(((} \]\[\texttt{加了快150ms} \]
1.最大流
分為複雜度\(O(nm^2)\)的EK和\(O(n^2m)\)的Dinic.
EK最大流模板:
//this code can get 81 points in P3381,which is a template problem. #include <bits/stdc++.h> #define int long long #define MAXN 2000001 #define INF 1e8+10 using namespace std; inline int r() { int fed=0; bool flag=1; char in=getchar(); while(!isdigit(in)) flag&=(in!='-'),in=getchar(); while(isdigit(in)) fed=fed*10+in-'0',in=getchar(); return (2*flag-1)*fed; } int n,m,s,t; int ans; int head[MAXN],cntr; int A[MAXN],path[MAXN]; struct edge{ int u,v,next,flow; }e[MAXN]; inline void add(int u,int v,int flow) { e[cntr].u=u; e[cntr].v=v; e[cntr].flow=flow; e[cntr].next=head[u]; head[u]=cntr++; } inline void orz(int u,int v,int flow) { add(u,v,flow); add(v,u,0); } inline void EK() { while(true) { memset(A,0,sizeof(A)); queue<int> q; q.push(s); A[s]=INF; while(!q.empty()) { int u=q.front(); q.pop(); for(int i=head[u];~i;i=e[i].next) { int v=e[i].v; if(!A[v]&&e[i].flow) { path[v]=i; A[v]=min(A[u],e[i].flow); q.push(v); } } if(A[t]) break; } if(!A[t]) break; for(int i=t;i!=s;i=e[path[i]].u) { e[path[i]].flow-=A[t]; e[path[i]^1].flow+=A[t]; } ans+=A[t]; } } signed main() { memset(head,-1,sizeof(head)); n=r(),m=r(); s=r(),t=r(); for(int i=1;i<=m;i++) { int u,v,w; u=r(),v=r(); w=r(); orz(u,v,w); } EK(); printf("%lld",ans); return 0; }
Dinic最大流模板:
//100 points in P3381. #include <bits/stdc++.h> #define ri register int #define int long long #define MAXN 1000001 using namespace std; const int INF=0x7fffffff; int n,m,s,t; int depth[MAXN],head[MAXN],cur[MAXN],cntr; //queue<int> q; struct node{ int to,next,flow; }e[MAXN<<2]; inline void add(int u,int v,int flow) { e[cntr].to=v; e[cntr].flow=flow; e[cntr].next=head[u]; head[u]=cntr++; } inline void orz(int u,int v,int flow) { add(u,v,flow); add(v,u,0); } inline int r() { int fed=0; char i=getchar(); bool flag=1; while(!isdigit(i)) flag&=(i!='-'),i=getchar(); while(isdigit(i)) fed=fed*10+i-'0',i=getchar(); return (2*flag-1)*fed; } int q[MAXN]; inline bool bfs() { memset(depth,-1,sizeof(depth)); depth[s]=1; cur[s]=head[s]; int l=0,r=1; q[++l]=s; while(l<=r) { int u=q[l++]; for(ri i=head[u];~i;i=e[i].next) { int v=e[i].to; if(depth[v]==-1&&e[i].flow) { depth[v]=depth[u]+1; q[++r]=v; cur[v]=head[v]; if(v==t) return true; } } } return 0; } inline int dfs(int now,int fl) { if(now==t||fl==0) return fl; int tflow=0; for(ri i=cur[now];~i&&tflow<fl;i=e[i].next) { cur[now]=i; int v=e[i].to; if(depth[v]==depth[now]+1&&e[i].flow) { int cf=dfs(v,min(e[i].flow,fl-tflow)); if(!cf) depth[v]=-1; e[i].flow-=cf; e[i^1].flow+=cf; tflow+=cf; } } return tflow; } inline void Dinic() { int res=0,ad=0; while(bfs()) { while(ad=dfs(s,INF)) res+=ad; } printf("%lld",res); } signed main() { n=r(),m=r(); s=r(),t=r(); memset(head,-1,sizeof(head)); for(ri i=1;i<=m;i++) { int u,v,w; u=r(),v=r();w=r(); orz(u,v,w); } Dinic(); return 0; }
2.最小費用最大流
目前只會寫SSP演算法,用SPFA替代Dinic裡的bfs來求最少花費的增廣路.
SSP模板:
#include <bits/stdc++.h> #define MAXN 50005 #define ri register int using namespace std; const int INF=0x3f3f3f3f; inline int r() { int fed=0; char in=getchar(); bool flag=1; while(!isdigit(in)) flag&=(in!='-'),in=getchar(); while(isdigit(in)) fed=fed*10+in-'0',in=getchar(); return (2*flag-1)*fed; } int n,m,s,t,cntr,head[MAXN]; int ans,res; int dist[MAXN]; bool vis[MAXN]; int q[MAXN<<2]; int cur[MAXN]; struct node{ int to,next,flow,cost; }e[MAXN<<2]; inline void add(int u,int v,int w,int c) { e[cntr].to=v; e[cntr].flow=w; e[cntr].cost=c; e[cntr].next=head[u]; head[u]=cntr++; } inline void orz(int u,int v,int w,int c) { add(u,v,w,c); add(v,u,0,-c); } inline bool SPFA() { //已死 //演算法 //重現 //光輝 //(↑) memset(dist,0x3f,sizeof(dist)); memcpy(cur,head,sizeof(head)); int l=0,r=1; q[++l]=s,dist[s]=0; vis[s]=1; while(l<=r) { int u=q[l++]; vis[u]=0; for(ri i=head[u];~i;i=e[i].next) { int v=e[i].to; if(e[i].flow&&dist[v]>dist[u]+e[i].cost) { dist[v]=dist[u]+e[i].cost; if(!vis[v]) vis[v]=1,q[++r]=v; } } } return dist[t]!=INF; } inline int dfs(int now,int maxfl) { if(now==t||maxfl==0) return maxfl; vis[now]=1; int cytti=0; for(ri i=cur[now];~i&&cytti<maxfl;i=e[i].next) { cur[now]=i; int v=e[i].to; if(!vis[v]&&e[i].flow&&dist[v]==dist[now]+e[i].cost) { int cf=dfs(v,min(e[i].flow,maxfl-cytti)); if(cf) { ans+=cf*e[i].cost; e[i].flow-=cf; e[i^1].flow+=cf; cytti+=cf; } } } vis[now]=0; return cytti; } inline void Dinic() { int ad=0; while(SPFA()) while(ad=dfs(s,INF)) res+=ad; printf("%d %d",res,ans); } int main() { memset(head,-1,sizeof(head)); n=r(),m=r(); s=r(),t=r(); for(ri i=1;i<=m;i++) { int u,v,w,c; u=r(),v=r(); w=r(),c=r(); orz(u,v,w,c); } Dinic(); return 0; }
\[\color{skyblue}{\texttt{And We,}} \]\[\color{skyblue}{\texttt{We Burn Faster Than Lights,}} \]\[\color{skyblue}{\texttt{Shine Across In The Night Sky,}} \]\[\color{skyblue}{\texttt{We Burn Faster Than Lights.}} \]\[\color{gold}{◢_◤} \]