网络流常用模板(个人习惯)
参考博客:https://blog.csdn.net/xiji333/article/details/102828419
最大流模板:
1 #include<bits/stdc++.h> 2 #define INF 0x3f3f3f3f 3 using namespace std; 4 //Dinic模板 除了顶点数和变数 基本不需要改动什么 5 const int maxn=1e4+5; 6 const int maxm=1e5+5; 7 8 struct Edge 9 { 10 int to,nxt,f; 11 }; //前向星存边 12 Edge edge[maxm<<1]; //边的空间至少要开两倍 因为有反向边的存在 13 int head[maxn],cur[maxn];//cur用于当前弧优化 14 int tot=1; //边的编号 15 int depth[maxn]; //用于bfs分层 16 int n,m,s,t; //定点数 边数 源点 汇点 17 18 inline void addedge(int u,int v,int dis) //加一条 u->v 容量为dis的边 那么自然要加一条 v->u 流量为0的反向边 19 { 20 edge[++tot].to=v,edge[tot].f=dis; 21 edge[tot].nxt=head[u]; 22 head[u]=tot; 23 edge[++tot].to=u,edge[tot].f=0; 24 edge[tot].nxt=head[v]; 25 head[v]=tot; 26 } 27 28 bool bfs() //bfs分层 29 { 30 memcpy(cur,head,sizeof(cur));//当前弧优化要用到 31 memset(depth,0,sizeof(depth));//初始化为0或-1均可 看个人习惯 32 queue<int> q; 33 depth[s]=1; //源点 34 q.push(s); 35 int fir,to; 36 while(!q.empty()) 37 { 38 fir=q.front(); 39 q.pop(); 40 for(int i=head[fir];i;i=edge[i].nxt) 41 { 42 to=edge[i].to; 43 if(edge[i].f&&!depth[to]) //对于前向边来说 该边的流量未满 对于后向边来说 该边有流量可退回 44 { 45 depth[to]=depth[fir]+1; 46 q.push(to); 47 } 48 } 49 } 50 return depth[t]; 51 } 52 //dfs 寻找多条增广路 53 int dfs(int u,int lim)//当前节点 当前流量 54 { 55 if(u==t)//汇点 56 return lim; 57 int v,temp,ans=0; 58 for(int i=cur[u];i;i=edge[i].nxt) 59 { 60 cur[u]=i; //当前弧优化 61 v=edge[i].to; 62 if(depth[v]==depth[u]+1&&edge[i].f) 63 { 64 temp=dfs(v,min(lim,edge[i].f)); 65 edge[i].f-=temp; 66 edge[i^1].f+=temp; 67 ans+=temp; 68 lim-=temp; //多路增广 EK算法在此处已经return了 69 if(!lim) //流入当前节点的流量已经用完了 就没必要继续寻找增广路了 70 break; 71 } 72 } 73 if(lim||!ans) //流没用完 或者该点对答案没有任何贡献 以后也没必要访问该点 74 depth[u]=0; 75 return ans; 76 } 77 78 int dinic() 79 { 80 int ans=0; //答案 81 while(bfs()) //分层 82 ans+=dfs(s,INF); //dfs找增广路 83 return ans; 84 } 85 86 int main() 87 { 88 while(~scanf("%d %d %d %d",&n,&m,&s,&t)) 89 { 90 memset(head,0,sizeof(head)); 91 tot=1; 92 int u,v,c; 93 for(int i=0;i<m;i++) 94 { 95 scanf("%d%d%d",&u,&v,&c); 96 addedge(u,v,c); 97 } 98 printf("%d\n",dinic()); 99 } 100 return 0; 101 }
1 #include<bits/stdc++.h> 2 #define INF 0x3f3f3f3f 3 using namespace std; 4 //ISAP模板 除了需要改变顶点数和边数 5 //还要改变 isap() 函数中循环体的判断 6 //和 dfs() 对depth数组的更改 7 const int maxn=1e4+5; 8 const int maxm=1e5+5; 9 10 struct Edge 11 { 12 int to,nxt,f; 13 }; //前向星存边 14 Edge edge[maxm<<1]; //边的空间至少要开两倍 因为有反向边的存在 15 int head[maxn],cur[maxn];//cur用于当前弧优化 16 int tot=1; //边的编号 17 int depth[maxn],cnt[maxn]; 18 int n,m,s,t; //定点数 边数 源点 汇点 19 20 inline void addedge(int u,int v,int dis) //加一条 u->v 容量为dis的边 那么自然要加一条 v->u 流量为0的反向边 21 { 22 edge[++tot].to=v,edge[tot].f=dis; 23 edge[tot].nxt=head[u]; 24 head[u]=tot; 25 edge[++tot].to=u,edge[tot].f=0; 26 edge[tot].nxt=head[v]; 27 head[v]=tot; 28 } 29 30 void bfs() //bfs处理出深度 31 { 32 memset(depth,0,sizeof(depth)); 33 memset(cnt,0,sizeof(cnt)); 34 queue<int> q; //注意 此处是从汇点开始 35 depth[t]=1,cnt[1]=1; //汇点 36 q.push(t); 37 int fir,to; 38 while(!q.empty()) 39 { 40 fir=q.front(); 41 q.pop(); 42 for(int i=head[fir];i;i=edge[i].nxt) 43 { 44 to=edge[i].to; 45 if(edge[i].f&&!depth[to]) 46 { 47 depth[to]=depth[fir]+1; 48 ++cnt[depth[to]]; 49 q.push(to); 50 } 51 } 52 } 53 } 54 55 int dfs(int u,int lim)//当前节点 当前流量 56 { 57 if(u==t)//汇点 58 return lim; 59 int v,temp,ans=0; 60 for(int i=cur[u];i;i=edge[i].nxt) 61 { 62 cur[u]=i; //当前弧优化 63 v=edge[i].to; 64 if(depth[v]==depth[u]-1&&edge[i].f) 65 { 66 temp=dfs(v,min(lim,edge[i].f)); 67 edge[i].f-=temp; 68 edge[i^1].f+=temp; 69 ans+=temp; 70 lim-=temp; //多路增广 71 if(!lim) //流入当前节点的流量已经用完了 就没必要继续寻找增广路了 72 break; 73 } 74 } 75 if(lim||!ans) //流没用完 或者该点对答案没用任何贡献 76 { 77 if(--cnt[depth[u]]==0) 78 depth[s]=n+1; 79 ++cnt[++depth[u]]; 80 } 81 return ans; 82 } 83 84 int isap() 85 { 86 int ans=0; //答案 87 bfs(); 88 while(depth[s]<=n) //分层 此处视 顶点个数 不同需要改变 89 { 90 memcpy(cur,head,sizeof(cur)); 91 ans+=dfs(s,INF); //dfs找增广路 92 } 93 return ans; 94 } 95 96 int main() 97 { 98 while(~scanf("%d %d %d %d",&n,&m,&s,&t)) 99 { 100 memset(head,0,sizeof(head)); 101 tot=1; 102 int u,v,c; 103 for(int i=0;i<m;i++) 104 { 105 scanf("%d%d%d",&u,&v,&c); 106 addedge(u,v,c); 107 } 108 printf("%d\n",isap()); 109 } 110 return 0; 111 }
最小费用最大流:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<queue> 5 #define INF 0x3f3f3f3f 6 using namespace std; 7 8 const int maxn=5005; 9 const int maxm=50005; 10 11 struct Edge 12 { 13 int to,nxt,f,w; 14 }edge[maxm<<1]; 15 16 int n,m,s,t,tot; 17 int head[maxn]; //前向星 18 int dis[maxn],pre[maxn],maxf[maxn],inque[maxn];//dis用于最短路 pre记录前驱边 maxf记录最小剩余容量 inque记录是否在队列中 19 20 inline void addedge(int u,int v,int c,int w)//容量为c 权值为w 21 { 22 edge[++tot].to=v,edge[tot].f=c,edge[tot].w=w,edge[tot].nxt=head[u],head[u]=tot; 23 edge[++tot].to=u,edge[tot].f=0,edge[tot].w=-w,edge[tot].nxt=head[v],head[v]=tot; 24 } 25 26 bool spfa() 27 { 28 queue<int> q; 29 q.push(s); 30 memset(dis,INF,sizeof(dis)); 31 dis[s]=0,inque[s]=1,maxf[s]=INF;//源点流量无限大 32 while(!q.empty()) 33 { 34 int u=q.front(); 35 q.pop(),inque[u]=0;; 36 for(int i=head[u];i;i=edge[i].nxt) 37 { 38 int v=edge[i].to; 39 if(edge[i].f&&dis[u]+edge[i].w<dis[v]) 40 { 41 dis[v]=dis[u]+edge[i].w; 42 pre[v]=i; //记录前驱边 43 maxf[v]=min(maxf[u],edge[i].f);//流入v的流量等于 二者的最小值 44 if(!inque[v]) 45 inque[v]=1,q.push(v); 46 } 47 } 48 } 49 if(dis[t]<INF) 50 return 1; 51 return 0; 52 } 53 54 void MCMF() 55 { 56 int mflow=0,mcost=0; 57 while(spfa()) 58 { 59 int u=t,v; 60 while(u!=s) 61 { 62 v=pre[u]; 63 edge[v].f-=maxf[t]; 64 edge[v^1].f+=maxf[t]; 65 u=edge[v^1].to; 66 } 67 mflow+=maxf[t]; 68 mcost+=dis[t]*maxf[t]; 69 } 70 printf("%d %d\n",mflow,mcost); 71 } 72 73 int main() 74 { 75 while(~scanf("%d%d%d%d",&n,&m,&s,&t)) 76 { 77 tot=1; 78 memset(head,0,sizeof(head)); 79 int u,v,f,w; 80 for(int i=0;i<m;i++) 81 { 82 scanf("%d%d%d%d",&u,&v,&f,&w); 83 addedge(u,v,f,w); 84 } 85 MCMF(); 86 } 87 }
学习视频(B站):https://www.bilibili.com/video/BV1Ke411x7Gh?from=search&seid=241181857404433824

浙公网安备 33010602011771号