zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    【iOS学习笔记】iOS启动顺序
    【iOS学习笔记】iOS算法(四)之冒泡排序
    【iOS学习笔记】iOS算法(五)之折半查找
    【iOS学习笔记】iOS算法(三)之插入排序
    【iOS学习笔记】iOS算法(二)之选择排序
    【iOS学习笔记】iOS算法(一)快速排序算法
    【iOS学习笔记】iOS ⾃自定义cell的步骤
    【iOS学习笔记】IOS开发中设置applicationIconBadgeNumber和消息推送
    【iOS学习笔记】iOS 9:改用更安全的HTTPS
    2015/10/6 iOS 笔记 细节 应用中常见文件
  • 原文地址:https://www.cnblogs.com/mogeko/p/11249271.html
Copyright © 2011-2022 走看看