网络流常用模板(个人习惯)

参考博客: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 }
dinic
  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 }
isap

最小费用最大流:

 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 }
spfa版本

学习视频(B站):https://www.bilibili.com/video/BV1Ke411x7Gh?from=search&seid=241181857404433824

posted @ 2020-07-10 20:54  麦客_zeng  阅读(181)  评论(0)    收藏  举报