Luogu P3381 【模板】最小费用最大流

传送门

最小费用最大流,就是在求最大流的前提下,使选出的路径费用最小。

每条边除了容量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;
}
View Code

猜你喜欢

转载自www.cnblogs.com/mogeko/p/11249271.html