网络流--费用流Ek算法讲解
前一篇博客写的是最大流。先简要说一下思路,方便下面的讲解。
最大流求解是先跑一遍bfs,把每个点定义一个深度,跑dfs的同时连接一条反向边方便反悔,避免不必要的时间。
现在说一下费用流。
费用流的全称是最小费用最大流(或最大费用最大流),保证最小费用的情况下跑最大流。
最小费用?
BFS -> SPFA成功解决。
我们不需要再给每个点定义深度,而是直接把费用当成边权求一遍到原点的最短路。
但是,流量的反向边初始值为0,费用是0吗?
显然不是,因为如果不需要走这条边显然是不需要费用的,所以正向边+反向边的费用为0.显然费用为-cost。
下一个问题,如果我们找到了最短路,如何寻找路径把费用累加并更改流量?
SPFA解决!
之后我们当前dfs的流量需要用一个数组存起来,而不是一个变量。
之后就没什么了,不会的问我。
题目描述
如题,给出一个网络图,以及其源点和汇点,每条边已知其最大流量和单位流量费用,求出其网络最大流和在最大流情况下的最小费用。
输入格式:
第一行包含四个正整数N、M、S、T,分别表示点的个数、有向边的个数、源点序号、汇点序号。
接下来M行每行包含四个正整数ui、vi、wi、fi,表示第i条有向边从ui出发,到达vi,边权为wi(即该边最大流量为wi),单位流量的费用为fi。
输出格式:
一行,包含两个整数,依次为最大流量和在最大流量情况下的最小费用。
样例输入:
4 5 4 3
4 2 30 2
4 3 20 3
2 3 20 1
2 1 30 9
1 3 40 5
样例输出:
50 280
code:
#include<cstdio> #include<algorithm> #include<queue> #include<cstring> using namespace std; #define N 100000 int n,m,S,T; int f[N]; int now[N]; int head[N]; int to[N]; int val[N]; int nex[N]; int cost[N]; int idx=1; int inq[N]; int pre[N]; int maxflow; int ans; int a,b,c,d; int nowflow[N]; void addedge(int a,int b,int c,int d) { nex[++idx]=head[a]; head[a]=idx; to[idx]=b; val[idx]=c; cost[idx]=d; } bool spfa(int S,int T) { queue<int > q; memset(f,0x3f,sizeof(f)); memset(inq,0,sizeof(inq)); memset(nowflow,0x3f,sizeof(nowflow)); q.push(S); f[S]=0; inq[S]=1; //cost[S]=1<<30; while(!q.empty()) { int x=q.front(); inq[x]=0; q.pop(); for(int i=head[x];i;i=nex[i]) { if(val[i]>0&&f[to[i]]>f[x]+cost[i]) { f[to[i]]=f[x]+cost[i]; nowflow[to[i]]=min(nowflow[x],val[i]); pre[to[i]]=i; if(!inq[to[i]]) { inq[to[i]]=1; q.push(to[i]); } } } } if(f[T]>=0x3f3f3f3f) return 0; return 1; } void EK() { int x=T; while(x!=S) { int i=pre[x]; val[i]-=nowflow[T]; val[i^1]+=nowflow[T]; x=to[i^1]; } maxflow+=nowflow[T]; ans+=f[T]*nowflow[T]; } int main() { scanf("%d%d%d%d",&n,&m,&S,&T); for(int i=1;i<=m;i++) { scanf("%d%d%d%d",&a,&b,&c,&d); addedge(a,b,c,d); addedge(b,a,0,-d); } while(spfa(S,T)) EK(); printf("%d %d",maxflow,ans); }