网络流——最小费用最大流模板

Posted amaris-diana

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了网络流——最小费用最大流模板相关的知识,希望对你有一定的参考价值。

 

 

#zkw费用流#

参考网址: https://artofproblemsolving.com/community/c1368h1020435

zkw大佬的改进:①在dfs的时候可以实现多路增广②KM算法节省SPFA时间(然而我这里没有KM,要问为什么,当然是因为我不会了orz);

but,参考了另外的博客,修修补补又三年~

技术图片
  1 #include <algorithm>
  2 #include <iostream>
  3 #include <cstring>
  4 #include <cstdio>
  5 #include <queue>
  6 #include <cmath>
  7 using namespace std;
  8 const int maxv= 200010;
  9 const int maxe= 2000010;
 10 const int INF= 0x3f3f3f3f;
 11 
 12 struct ENode
 13 
 14     int to;
 15     int c;
 16     int f;
 17     int Next;
 18 ;
 19 ENode edegs[maxe];
 20 int Head[maxv], tnt;
 21 void init()
 22 
 23     memset(Head, -1, sizeof(Head));
 24     tnt= -1;
 25 
 26 void Add_ENode(int a, int b, int _c, int _f)
 27 
 28     ++ tnt;
 29     edegs[tnt].to= b;
 30     edegs[tnt].c= _c;
 31     edegs[tnt].f= _f;
 32     edegs[tnt].Next= Head[a];
 33     Head[a]= tnt;
 34     ++ tnt;
 35     edegs[tnt].to= a;
 36     edegs[tnt].c= 0;
 37     edegs[tnt].f= -_f;
 38     edegs[tnt].Next= Head[b];
 39     Head[b]= tnt;
 40 
 41 
 42 bool vis[maxv];  //访问标记
 43 int dist[maxv];  //每个点的距离标号,其实就是dis[];
 44 inline bool spfa(int s, int t)
 45 
 46     memset(vis, 0, sizeof(vis));
 47     memset(dist, INF, sizeof(dist));
 48     dist[t]= 0;
 49     vis[t]= 1;//首先SPFA我们维护距离标号的时候要倒着跑,这样可以维护出到终点的最短路径
 50     deque<int> q;
 51     q.push_back(t);//使用了SPFA的SLF优化(SLF可以自行百度或Google)
 52 
 53     while(!q.empty())
 54     
 55         int u= q.front();
 56         q.pop_front();
 57         for(int k= Head[u]; k!= -1; k=edegs[k].Next)
 58         
 59             int v= edegs[k].to;
 60             if(edegs[k^1].c&& dist[v]> dist[u]- edegs[k].f)
 61             
 62                 /*首先c[k^1]是为什么呢,因为我们要保证正流,但是SPFA是倒着跑的,
 63                 所以说我们要求c[k]的对应反向边是正的,这样保证走的方向是正确的*/
 64                 dist[v]= dist[u]- edegs[k].f;
 65                 /*因为已经是倒着的了,我们也可以很清楚明白地知道建边的时候反向边的边权是负的,
 66                 所以减一下就对了(负负得正)*/
 67                 if(!vis[v])
 68                 
 69                     vis[v]= 1;
 70                     /*SLF优化*/
 71                     if(! q.empty()&& dist[v]< dist[q.front()])q.push_front(v);
 72                     else q.push_back(v);
 73                 
 74             
 75         
 76         vis[u]=0;
 77     
 78     return dist[s]< INF;//判断起点终点是否连通
 79 
 80 
 81 int ans; //ans:费用答案
 82 inline int dfs_flow(int now, int c_max, int t)
 83 
 84     /*这里就是进行増广了,一次dfs进行了多次增广*/
 85     if(now== t)
 86     
 87         vis[t]=1;
 88         return c_max;
 89     
 90     int ret= 0, a;
 91     vis[now]=1;
 92 
 93     for(int k=Head[now]; k!= -1; k= edegs[k].Next)
 94     
 95         int v= edegs[k].to;
 96         if(! vis[v]&& edegs[k].c&& dist[v]== dist[now]- edegs[k].f)
 97         
 98             /*这个条件就表示这条边可以进行増广*/
 99             a= dfs_flow(v, min(edegs[k].c, c_max- ret), t);
100             if(a)
101             
102                 /*累加答案,加流等操作都在这了*/
103                 ans+= a* edegs[k].f; /*流过时按流量单位计费*/
104                 //ans+= edegs[k].f; /*流过时费用固定*/
105                 /**注意上面两句指令的区别*/
106                 edegs[k].c-= a;
107                 edegs[k^1].c+= a;
108                 ret+= a;
109             
110             if(ret== c_max)break;
111         
112     
113     return ret;
114 
115 
116 inline int Min_Cost_Flow(int s, int t)
117 
118     int flow= 0;
119     ans= 0;  //费用清零
120     while(spfa(s, t))
121     
122         /*判断起点终点是否连通,不连通说明满流,做完了退出*/
123         vis[t]= 1;
124         while(vis[t])
125         
126             memset(vis, 0, sizeof vis);
127             flow+= dfs_flow(s, INF, t);//一直増广直到走不到为止(这样也可以省时间哦)
128         
129     
130     return flow;//这里返回的是最大流,费用的答案在ans里
131 
132 int main()
133 
134     int n, m, s, t;
135     scanf("%d %d %d %d", &n, &m, &s, &t);
136     init();
137     for(int i= 0; i< m; i ++)
138     
139         int a, b, c, f;
140         scanf("%d%d%d%d", &a, &b, &c, &f);
141         Add_ENode(a, b, c, f);
142     
143     printf("%d ", Min_Cost_Flow(s, t));
144     printf("%d\n", ans);
145     return 0;
146 
View Code

 

 

 

 

 

 

end;

以上是关于网络流——最小费用最大流模板的主要内容,如果未能解决你的问题,请参考以下文章

网络流——最小费用最大流模板

模板最小费用最大流

模板最小费用最大流

最小费用最大流(luogu P3381 模板最小费用最大流)

[洛谷P3381]模板最小费用最大流

最小费用最大流基础模板(洛谷3381)