最小费用最大流,就是在求最大流的前提下,使选出的路径费用最小。
每条边除了容量w[]外,还要记录一个单位流量费用co[]。
其实就是$dinic$的$bfs$和$SPFA$同时进行,
每次更新增广路时,保证选择的一定是费用最小的一条路径。
($paopo$说这个用不了当前弧优化,所以我就没用qwq)
对于每个点,记录以下变量:
- fa[]:最短路上的祖先
- path[]:连接该点与祖先的边的序号
- dis[]:从源点s到该点最短路的费用
- fl[]:该点的最大流
初始化:每次将dis[],fl[]设置为INF。将源点s压入队列,dis[]为0,vis[]为true。
每次弹出队首,将vis[]改为false,检查其连的每一条边能否更新最短路,并更新上述变量。
若没有访问过这一点,则压入队列。
bool SPFA() { memset(dis,INF,sizeof(dis)); memset(fl,INF,sizeof(fl)); queue <int> q; dis[s] = 0; vis[s] = true; q.push(s); while(!q.empty()) { int u = q.front(); q.pop(); vis[u] = false; for(int i = head[u]; i != -1; i = nxt[i]) { int v = to[i]; if(dis[u]+co[i] >= dis[v] || !w[i]) continue; fa[v] = u; path[v] = i; dis[v] = dis[u]+co[i]; fl[v] = min(fl[u],w[i]); if(!vis[v]) { vis[v] = true; q.push(v); } } } if(dis[t] == INF) return false; return true; }
$bfs$结束后,不用$dfs$,直接从汇点t不断寻找祖先,
将这条最短路上的每条边的容量都减去流入汇点的流量fl[t],并更新最大流、最小费用。
void mcmf() { while(SPFA()) { for(int i = t; i != s; i = fa[i]) { int p = path[i]; w[p] -= fl[t]; w[p^1] += fl[t]; } maxflow += fl[t]; mincost += fl[t]*dis[t]; } }
完整代码如下
#include<cstdio> #include<iostream> #include<cmath> #include<cstring> #include<queue> #define MogeKo qwq using namespace std; const int maxn = 2e5+10; const int INF = 0x3f3f3f3f; int n,m,s,t,a,b,c,d,cnt,ans; int head[maxn],to[maxn],nxt[maxn],w[maxn],co[maxn]; int fa[maxn],path[maxn],dis[maxn],fl[maxn]; int mincost,maxflow; bool vis[maxn]; void add(int x,int y,int ww,int cc) { to[cnt] = y; nxt[cnt] = head[x]; head[x] = cnt; w[cnt] = ww; co[cnt++] = cc; } bool SPFA() { memset(dis,INF,sizeof(dis)); memset(fl,INF,sizeof(fl)); queue <int> q; dis[s] = 0; vis[s] = true; q.push(s); while(!q.empty()) { int u = q.front(); q.pop(); vis[u] = false; for(int i = head[u]; i != -1; i = nxt[i]) { int v = to[i]; if(dis[u]+co[i] >= dis[v] || !w[i]) continue; fa[v] = u; path[v] = i; dis[v] = dis[u]+co[i]; fl[v] = min(fl[u],w[i]); if(!vis[v]) { vis[v] = true; q.push(v); } } } if(dis[t] == INF) return false; return true; } void mcmf() { while(SPFA()) { for(int i = t; i != s; i = fa[i]) { int p = path[i]; w[p] -= fl[t]; w[p^1] += fl[t]; } maxflow += fl[t]; mincost += fl[t]*dis[t]; } } int main() { scanf("%d%d%d%d",&n,&m,&s,&t); memset(head,-1,sizeof(head)); for(int i = 1; i <= m; i++) { scanf("%d%d%d%d",&a,&b,&c,&d); add(a,b,c,d); add(b,a,0,-d); } mcmf(); printf("%d %d",maxflow,mincost); return 0; }