网络流模板们

最大流EK:

 1 #include <vector>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 #define N1 210
 6 #define M1 1010
 7 #define ll long long
 8 #define dd double
 9 #define inf 0x3f3f3f3f
10 using namespace std;
11 
12 int gint()
13 {
14     int ret=0,fh=1;char c=getchar();
15     while(c<'0'||c>'9'){if(c=='-')fh=-1;c=getchar();}
16     while(c>='0'&&c<='9'){ret=ret*10+c-'0';c=getchar();}
17     return ret*fh;
18 }
19 
20 struct Edge{
21 int head[N1],to[M1<<1],nxt[M1<<1],val[M1<<1],cte;
22 void ae(int u,int v,int w)
23 {
24     cte++; to[cte]=v; val[cte]=w;
25     nxt[cte]=head[u]; head[u]=cte;
26 }
27 }e;
28 
29 int que[N1],hd,tl;
30 int flow[N1],id[N1];
31 
32 int bfs(int S,int T)
33 {
34     int x,j,v;
35     memset(flow,0,sizeof(flow));
36     memset(id,0,sizeof(id));
37     hd=1,tl=0; que[++tl]=S; flow[S]=inf;
38     while(hd<=tl)
39     {
40         x=que[hd++];
41         for(j=e.head[x];j;j=e.nxt[j])
42         {
43             v=e.to[j]; 
44             if(id[v]||e.val[j]==0) continue;
45             flow[v]=min(flow[x],e.val[j]);
46             id[v]=j; que[++tl]=v;
47         }
48     }
49     if(!flow[T]) return -1;
50     else return flow[T];
51 }
52 
53 int EK(int S,int T)
54 {
55     int x,mxflow=0,tmp;
56     while(1)
57     {
58         tmp=bfs(S,T); 
59         if(tmp==-1) return mxflow;
60         for(x=T;x!=S;x=e.to[id[x]^1])
61         {
62             e.val[id[x]]-=tmp;
63             e.val[id[x]^1]+=tmp;
64         }
65         mxflow+=tmp;
66     }
67 }
68 
69 int n,m,S,T;
70 
71 int main()
72 {
73     scanf("%d%d%d%d",&n,&m,&S,&T);
74     int i,j,k,x,y,z; e.cte=1;
75     for(i=1;i<=m;i++){ x=gint(); y=gint(); z=gint(); e.ae(x,y,z); e.ae(y,x,0); }
76     printf("%d
",EK(S,T));
77     return 0;
78 }
View Code

最大流Dinic:

 1 #include <vector>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 #define N1 10010
 6 #define M1 100010
 7 #define ll long long
 8 #define dd double
 9 #define inf 0x3f3f3f3f
10 using namespace std;
11 
12 int gint()
13 {
14     int ret=0,fh=1;char c=getchar();
15     while(c<'0'||c>'9'){if(c=='-')fh=-1;c=getchar();}
16     while(c>='0'&&c<='9'){ret=ret*10+c-'0';c=getchar();}
17     return ret*fh;
18 }
19 
20 struct Edge{
21 int head[N1],to[M1<<1],nxt[M1<<1],val[M1<<1],cte;
22 void ae(int u,int v,int w)
23 {
24     cte++; to[cte]=v; val[cte]=w;
25     nxt[cte]=head[u]; head[u]=cte;
26 }
27 }e;
28 
29 int que[N1],hd,tl,dep[N1],now[N1];
30 int n,m,S,T,mxflow; 
31 
32 int bfs()
33 {
34     int x,j,v;
35     memset(dep,-1,sizeof(dep));
36     memcpy(now,e.head,sizeof(e.head));
37     hd=1,tl=0; que[++tl]=S; dep[S]=0;
38     while(hd<=tl)
39     {
40         x=que[hd++];
41         for(j=e.head[x];j;j=e.nxt[j])
42         {
43             v=e.to[j];
44             if(dep[v]!=-1||!e.val[j]) continue;
45             dep[v]=dep[x]+1; que[++tl]=v;
46         }
47     }
48     if(dep[T]==-1) return 0;
49     else return 1;
50 }
51 
52 int dfs(int u,int limit)
53 {
54     if(!limit||u==T) return limit;
55     int j,v,flow,ans=0;
56     for(j=now[u];j;j=e.nxt[j])
57     {
58         now[u]=j; v=e.to[j]; 
59         if(dep[v]==dep[u]+1 && (flow=dfs(v,min(limit,e.val[j]))) )
60         {
61             limit-=flow; ans+=flow;
62             e.val[j]-=flow; e.val[j^1]+=flow;
63             if(!limit) break;
64         }
65     }
66     return ans;
67 }
68 
69 int Dinic()
70 {
71     while(bfs())
72     {
73         mxflow+=dfs(S,inf);
74     }
75     return mxflow;
76 }
77 
78 
79 int main()
80 {
81     scanf("%d%d%d%d",&n,&m,&S,&T);
82     int i,x,y,z,ans=0; e.cte=1;
83     for(i=1;i<=m;i++){ x=gint(); y=gint(); z=gint(); e.ae(x,y,z); e.ae(y,x,0); }
84     ans=Dinic();
85     printf("%d
",ans);
86     return 0;
87 }
View Code

费用流spfaEK:

 1 #include <vector>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 #define N1 5010
 6 #define M1 50010
 7 #define ll long long
 8 #define dd double
 9 #define inf 0x3f3f3f3f
10 using namespace std;
11 
12 int gint()
13 {
14     int ret=0,fh=1;char c=getchar();
15     while(c<'0'||c>'9'){if(c=='-')fh=-1;c=getchar();}
16     while(c>='0'&&c<='9'){ret=ret*10+c-'0';c=getchar();}
17     return ret*fh;
18 }
19 
20 int n,m,S,T;
21 struct Edge{
22 int head[N1],to[M1<<1],nxt[M1<<1],val[M1<<1],flow[M1<<1],cte;
23 void ae(int u,int v,int F,int W)
24 {
25     cte++; to[cte]=v; flow[cte]=F; val[cte]=W; 
26     nxt[cte]=head[u]; head[u]=cte;
27 }
28 }e;
29 
30 int que[M1<<1],dis[N1],flow[N1],use[N1],id[N1],hd,tl;
31 
32 int spfa()
33 {
34     int x,j,v;
35     memset(dis,0x3f,sizeof(dis)); memset(flow,0,sizeof(flow)); memset(use,0,sizeof(use));
36     hd=1,tl=0; que[++tl]=S; dis[S]=0; use[S]=1; flow[S]=inf;
37     while(hd<=tl)
38     {
39         x=que[hd++];
40         for(j=e.head[x];j;j=e.nxt[j])
41         {
42             v=e.to[j];
43             if(e.flow[j]>0&&dis[v]>dis[x]+e.val[j])
44             {
45                 dis[v]=dis[x]+e.val[j]; id[v]=j;
46                 flow[v]=min(flow[x],e.flow[j]);
47                 if(!use[v]) que[++tl]=v,use[v]=1;
48             }
49         }
50         use[x]=0;
51     }
52     return dis[T]!=inf;
53 }
54 
55 int mxflow=0,tot_cost=0;
56 void EK()
57 {
58     int x; mxflow=0,tot_cost=0;
59     while(spfa())
60     {
61         mxflow+=flow[T]; tot_cost+=dis[T]*flow[T];
62         for(x=T;x!=S;x=e.to[id[x]^1])
63         {
64             e.flow[id[x]]-=flow[T];
65             e.flow[id[x]^1]+=flow[T];
66         }
67     }
68 }
69 
70 
71 int main()
72 {
73     scanf("%d%d%d%d",&n,&m,&S,&T);
74     int i,a,b,c,d; e.cte=1;
75     for(i=1;i<=m;i++)
76     {
77         scanf("%d%d%d%d",&a,&b,&c,&d);
78         e.ae(a,b,c,d); e.ae(b,a,0,-d);
79     }
80     EK();
81     printf("%d %d
",mxflow,tot_cost);
82     return 0;
83 }
View Code

无源汇上下界可行流:

给定一张图,每条边都有对应的流量限制$[l,r]$,要求每条边的流量都在规定范围内

我们想办法去掉流量下界的限制,每条边流量上限改成$r-l$,然后跑最大流就行了

直接去掉是不行的

假设每条边都流了流量下界l点流量,此时一些点可能并不满足流量守恒

而我们最终建出来的网络流图中,每个点的出入流量显然是守恒的(除了源汇)

所以我们把点向源点汇点连边来让它流量守恒

具体做法是,手动建出源$S$汇$T$

点$x$的最小入流量$>$最小出流量,$S$向$x$连流量为差值的边,反之$x$向$T$连流量为差值的边

模拟出原图中流量下界对点的影响

然后跑最大流,每条边的实际流量=最小割后的流量+流量下界

如果在最小割图中源汇连出去的边没流满,说明有边的流量下界没达到,一定无解

  1 #include <cmath>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <algorithm>
  5 #define N1 210
  6 #define M1 40010
  7 #define ll long long
  8 using namespace std;
  9 const int inf=0x3f3f3f3f;
 10 
 11 int gint()
 12 {
 13     int ret=0,fh=1; char c=getchar();
 14     while(c<'0'||c>'9'){if(c=='-')fh=-1;c=getchar();}
 15     while(c>='0'&&c<='9'){ret=ret*10+c-'0';c=getchar();}
 16     return ret*fh;
 17 }
 18 struct Edge{
 19 int to[M1<<1],nxt[M1<<1],flow[M1<<1],val[M1<<1],head[N1],cte;
 20 void ae(int u,int v,int f,int w)
 21 {
 22     cte++; to[cte]=v; nxt[cte]=head[u];
 23     head[u]=cte; flow[cte]=f; val[cte]=w;
 24 }
 25 }e;
 26 
 27 int n,m,S,T,hd,tl;
 28 int dep[N1],cur[N1],que[M1];
 29 
 30 int bfs()
 31 {
 32     int x,j,v;
 33     memset(dep,-1,sizeof(dep)); memcpy(cur,e.head,sizeof(cur));
 34     hd=1,tl=0; que[++tl]=S; dep[S]=0;
 35     while(hd<=tl)
 36     {
 37         x=que[hd++];
 38         for(j=e.head[x];j;j=e.nxt[j])
 39         {
 40             v=e.to[j]; 
 41             if( e.flow[j]>0 && dep[v]==-1 )
 42             {
 43                 dep[v]=dep[x]+1;
 44                 que[++tl]=v;
 45             }
 46         }
 47     }
 48     return dep[T]!=-1;
 49 }
 50 int dfs(int x,int limit)
 51 {
 52     if( (x==T) || (!limit) ) return limit;
 53     int j,v,flow,ans=0;
 54     for(j=cur[x];j;j=e.nxt[j])
 55     {
 56         cur[x]=j; v=e.to[j];
 57         if( (dep[v]==dep[x]+1) && ( flow=dfs(v,min(limit,e.flow[j])) ) )
 58         {
 59             e.flow[j]-=flow; limit-=flow;
 60             e.flow[j^1]+=flow; ans+=flow;
 61             if(!limit) break;
 62         }
 63     }
 64     return ans;
 65 }
 66 int Dinic()
 67 {
 68     int mxflow=0;
 69     while( bfs() )
 70     {
 71         mxflow+=dfs(S,inf);
 72     }
 73     return mxflow;
 74 }
 75 int ouc[N1],id[M1],Flow[M1];
 76 
 77 int main()
 78 {
 79     int i,j,x,y,v,l,r,ans; 
 80     scanf("%d%d",&n,&m); 
 81     S=0,T=n+1; e.cte=1;
 82     for(i=1;i<=m;i++) 
 83     {
 84         x=gint(), y=gint(), l=gint(), r=gint();
 85         e.ae(x,y,r-l,l); id[e.cte]=i; e.ae(y,x,0,l); 
 86         ouc[x]+=l; ouc[y]-=l; 
 87     }
 88     for(x=1;x<=n;x++) 
 89         if(ouc[x]<0) e.ae(S,x,-ouc[x],0), e.ae(x,S,0,0);
 90         else e.ae(x,T,ouc[x],0), e.ae(T,x,0,0);
 91     ans=Dinic();
 92     for(j=e.head[S];j;j=e.nxt[j])
 93     {
 94         v=e.to[j];
 95         if(e.flow[j]>0){ puts("NO"); return 0; }
 96     }
 97     for(j=e.head[T];j;j=e.nxt[j])
 98     {
 99         v=e.to[j]; 
100         if(e.flow[j^1]>0){ puts("NO"); return 0; }
101     }
102     puts("YES");
103     for(x=1;x<=n;x++)
104     for(j=e.head[x];j;j=e.nxt[j])
105     {
106         v=e.to[j];
107         if(!(j&1)) Flow[id[j]]=e.flow[j^1]+e.val[j];
108     }
109     for(i=1;i<=m;i++)
110         printf("%d
",Flow[i]);
111     return 0;
112 }
View Code

有源汇上下界最大流:

给定一张有源汇网络流图,每条边都有对应的流量限制$[l,r]$,要求每条边的流量都在规定范围内,求最大流

设$s$是原图源点,$t$是原图汇点,$S$是新建源点,$T$是新建汇点

先判断是否有可行流

已经给定了源汇,咋办? 

因为$s$流出流量=$t$流入流量

所以$t$向$s$连一条流量为$inf$的边,就变成了无源汇上下界可行流问题

在残量网络中,可行流的部分已经被去掉了

那么$s$到$t$还可能有流量流过,以$s,t$为源点在残量网络中跑最大流即可

  1 #include <cmath>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <algorithm>
  5 #define N1 210
  6 #define M1 40010
  7 #define ll long long
  8 using namespace std;
  9 const int inf=0x3f3f3f3f;
 10 
 11 int gint()
 12 {
 13     int ret=0,fh=1; char c=getchar();
 14     while(c<'0'||c>'9'){if(c=='-')fh=-1;c=getchar();}
 15     while(c>='0'&&c<='9'){ret=ret*10+c-'0';c=getchar();}
 16     return ret*fh;
 17 }
 18 struct Edge{
 19 int to[M1<<1],nxt[M1<<1],flow[M1<<1],head[N1],cte;
 20 void ae(int u,int v,int f)
 21 {
 22     cte++; to[cte]=v; nxt[cte]=head[u];
 23     head[u]=cte; flow[cte]=f; //val[cte]=w;
 24 }
 25 }e;
 26 
 27 int n,m,s,t,S,T,hd,tl;
 28 int dep[N1],cur[N1],que[M1];
 29 
 30 int bfs()
 31 {
 32     int x,j,v;
 33     memset(dep,-1,sizeof(dep)); memcpy(cur,e.head,sizeof(cur));
 34     hd=1,tl=0; que[++tl]=S; dep[S]=0;
 35     while(hd<=tl)
 36     {
 37         x=que[hd++];
 38         for(j=e.head[x];j;j=e.nxt[j])
 39         {
 40             v=e.to[j]; 
 41             if( e.flow[j]>0 && dep[v]==-1 )
 42             {
 43                 dep[v]=dep[x]+1;
 44                 que[++tl]=v;
 45             }
 46         }
 47     }
 48     return dep[T]!=-1;
 49 }
 50 int dfs(int x,int limit)
 51 {
 52     if( (x==T) || (!limit) ) return limit;
 53     int j,v,flow,ans=0;
 54     for(j=cur[x];j;j=e.nxt[j])
 55     {
 56         cur[x]=j; v=e.to[j];
 57         if( (dep[v]==dep[x]+1) && ( flow=dfs(v,min(limit,e.flow[j])) ) )
 58         {
 59             e.flow[j]-=flow; limit-=flow;
 60             e.flow[j^1]+=flow; ans+=flow;
 61             if(!limit) break;
 62         }
 63     }
 64     return ans;
 65 }
 66 int Dinic()
 67 {
 68     int mxflow=0;
 69     while( bfs() )
 70         mxflow+=dfs(S,inf);
 71     return mxflow;
 72 }
 73 int ouc[N1]; 
 74 
 75 int main()
 76 {
 77     int i,j,x,y,v,l,r,ans; 
 78     scanf("%d%d%d%d",&n,&m,&s,&t); 
 79     S=0,T=n+1; e.cte=1;
 80     for(i=1;i<=m;i++) 
 81     {
 82         x=gint(), y=gint(), l=gint(), r=gint();
 83         e.ae(x,y,r-l); e.ae(y,x,0); 
 84         ouc[x]+=l; ouc[y]-=l; 
 85     }
 86     for(x=1;x<=n;x++) 
 87         if(ouc[x]<0) e.ae(S,x,-ouc[x]), e.ae(x,S,0);
 88         else e.ae(x,T,ouc[x]), e.ae(T,x,0);
 89     e.ae(t,s,inf); e.ae(s,t,0);
 90     ans=Dinic(); S=0, T=n+1;
 91     for(j=e.head[S];j;j=e.nxt[j])
 92     {
 93         v=e.to[j];
 94         if(e.flow[j]>0){ puts("please go home to sleep"); return 0; }
 95     }
 96     for(j=e.head[T];j;j=e.nxt[j])
 97     {
 98         v=e.to[j]; 
 99         if(e.flow[j^1]>0){ puts("please go home to sleep"); return 0; }
100     }
101     S=s, T=t;
102     ans=Dinic();
103     printf("%d
",ans);
104     return 0;
105 }
View Code

有源汇上下界最小流:

给定一张有源汇网络流图,每条边都有对应的流量限制$[l,r]$,要求每条边的流量都在规定范围内,求最小流

建图和有源汇上下界最大流一样

在跑完可行流以后,先断开t->s这条边,再以t为源点,s为汇点跑最大流

答案是可行流后t->s这条边的流量+t到s的最大流

为什么是可行流t->s这条边的流量而不是最大流?

可行流仅仅是可行的,不一定是最小的

假设最小入流量$>$最小出流量的点称为入点,反之为出点

在跑可行流时,必需的可行流是这样流的:S->入点->t->s->出点->T

事实上,我们模拟的是这样一个过程:s->出点->入点->t

假如有一条流量是这样的:S->入点->出点->T

它模拟的是这样的过程:出点->入点

这种流量对于可行流而言是多余的,它应该在第二次从t->s这条流量里被冲掉

但由于它并不连接s,t导致它不会被干掉,所以这种情况并不能算到答案里

  1 #include <cmath>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <algorithm>
  5 #define N1 50010
  6 #define M1 200010
  7 #define ll long long
  8 using namespace std;
  9 const ll inf=0x3f3f3f3f3f3fll;
 10 
 11 int gint()
 12 {
 13     int ret=0,fh=1; char c=getchar();
 14     while(c<'0'||c>'9'){if(c=='-')fh=-1;c=getchar();}
 15     while(c>='0'&&c<='9'){ret=ret*10+c-'0';c=getchar();}
 16     return ret*fh;
 17 }
 18 struct Edge{
 19 int to[M1<<1],nxt[M1<<1],head[N1],cte; ll flow[M1<<1];
 20 void ae(int u,int v,ll f)
 21 {
 22     cte++; to[cte]=v; nxt[cte]=head[u];
 23     head[u]=cte; flow[cte]=f; //val[cte]=w;
 24 }
 25 }e;
 26 
 27 int n,m,s,t,S,T,hd,tl;
 28 int dep[N1],cur[N1],que[M1];
 29 
 30 int bfs()
 31 {
 32     int x,j,v;
 33     memset(dep,-1,sizeof(dep)); memcpy(cur,e.head,sizeof(cur));
 34     hd=1,tl=0; que[++tl]=S; dep[S]=0;
 35     while(hd<=tl)
 36     {
 37         x=que[hd++];
 38         for(j=e.head[x];j;j=e.nxt[j])
 39         {
 40             v=e.to[j]; 
 41             if( e.flow[j]>0 && dep[v]==-1 )
 42             {
 43                 dep[v]=dep[x]+1;
 44                 que[++tl]=v;
 45             }
 46         }
 47     }
 48     return dep[T]!=-1;
 49 }
 50 ll dfs(int x,ll limit)
 51 {
 52     if( (x==T) || (!limit) ) return limit;
 53     int j,v; ll flow,ans=0;
 54     for(j=cur[x];j;j=e.nxt[j])
 55     {
 56         cur[x]=j; v=e.to[j];
 57         if( (dep[v]==dep[x]+1) && ( flow=dfs(v,min(limit,e.flow[j])) ) )
 58         {
 59             e.flow[j]-=flow; limit-=flow;
 60             e.flow[j^1]+=flow; ans+=flow;
 61             if(!limit) break;
 62         }
 63     }
 64     return ans;
 65 }
 66 ll Dinic()
 67 {
 68     ll mxflow=0;
 69     while( bfs() )
 70         mxflow+=dfs(S,inf);
 71     return mxflow;
 72 }
 73 ll ouc[N1]; 
 74 
 75 int main()
 76 {
 77     int i,j,x,y,v,l,r; ll ans; 
 78     scanf("%d%d%d%d",&n,&m,&s,&t); 
 79     S=0,T=n+1; e.cte=1;
 80     for(i=1;i<=m;i++) 
 81     {
 82         x=gint(), y=gint(), l=gint(), r=gint();
 83         e.ae(x,y,r-l); e.ae(y,x,0); 
 84         ouc[x]+=l; ouc[y]-=l; 
 85     }
 86     for(x=1;x<=n;x++) 
 87         if(ouc[x]<0) e.ae(S,x,-ouc[x]), e.ae(x,S,0);
 88         else e.ae(x,T,ouc[x]), e.ae(T,x,0);
 89     e.ae(t,s,inf); e.ae(s,t,0);
 90     ans=Dinic(); S=0, T=n+1;
 91     for(j=e.head[S];j;j=e.nxt[j])
 92     {
 93         v=e.to[j];
 94         if(e.flow[j]>0){ puts("please go home to sleep"); return 0; }
 95     }
 96     for(j=e.head[T];j;j=e.nxt[j])
 97     {
 98         v=e.to[j]; 
 99         if(e.flow[j^1]>0){ puts("please go home to sleep"); return 0; }
100     }
101     for(j=e.head[t];j;j=e.nxt[j]) if(e.to[j]==s) 
102         ans=e.flow[j^1], e.flow[j]=0, e.flow[j^1]=0;
103     S=t, T=s;
104     ans-=Dinic();
105     printf("%lld
",ans);
106     return 0;
107 }
View Code
原文地址:https://www.cnblogs.com/guapisolo/p/10268891.html