最小费用最大流相关概念
费用流即在网络流的基础上,给每条边都加了费用(费用有正有负)。
增广路:它的最大流量取决于增广路上流量最小的边。短板效应,最大容量取决于最短木板。
求解费用流的思想:
- 在总流量最大的前提下求解总费用最小的流,即最小费用最大流。
- 通过SPFA算法进行增广,每一次增广之后都可以得出一个费用,所用费用相加即是最小费用。(因为SPFA是最短路算法,最短路使得每次增广的流的费用最小,所以所得即最小答案)
注意:如果存在两条边,但是费用不同的话无法合并。
可以有负权边,但是不能有负权圈。
求解算法:MCMF算法(即SPFA+EK)。(SPFA用来计算最小费用路径,即增广路)
最小费用最大流的变形:
- 最大费用最小流:在添边的时候交换位置即可;
- 最大费用最大流:在添边的时候把取边的费用的相反数,用最小费用最大流求解后对于答案取反,即可得到最大费用(权值)。见之后的博客POJ3680
引入SPFA
先复习一下SPFA(因为图中可能会出现负的费用,所以不能用Dijkstra。)
(但是,在没有负环、单纯求最短路径的情况下,不建议使用SPFA,而是用Dijkstra。)
SPFA时间复杂度分析:
如果图是随机生成的,时间复杂度为 O(KM)(K可以认为是个常数,m为边数,n为点数);
但是实际上SPFA的算法复杂度是 O(N*M),但是出题人可以构造出卡SPFA的数据,让SPFA超时。
https://www.luogu.com.cn/blog/83547/spfa-suan-fa-jiao-xue 可以看一下这一篇,用静态邻接表(也就是链式前向星)实现。
我的SPFA模板:
1 void spfa(int x) 2 { 3 for(int i=1; i<=N; i++) 4 { 5 dist[i]=inf; 6 book[i]=0; 7 } 8 dist[x]=0;//源点到自身距离为0 9 queue<int>Q; 10 q.push(s);//源点入队 11 book[x]=1; 12 while(!Q.empty()) 13 { 14 int u=Q.front(); 15 Q.pop(); 16 book[u]=0; 17 for(int i=head[u]; i!=-1; i=edge[i].next) 18 { 19 int v=edge[i].to; 20 if(dist[u]+edge[i].w<dist[v]) //如果不满足三角形不等式 21 { 22 dist[v]=dist[u]+edge[i].w;//更新答案 23 if(book[v]==0) //如果不在队列 24 { 25 Q.push(v);//则入队 26 book[v]=1;//进行标记 27 } 28 } 29 } 30 } 31 }
有待学习:
待解决:
- 不明白为什么最小费用最大流中可以有负权边,但是不能有负权圈???