zoukankan      html  css  js  c++  java
  • 网络流之最小费用最大流

    最小费用最大流?

      最小费用最大流就是在最大流的基础上,给每条边一个单位花费,要在保证是最大流的情况下找出最小费用。这里的单位花费就是这条边的每一单位流量的花费。

    解法:

      先看这里的花费,假设第i条边的花费是wi,那么假设找到 了一条增广路(与最大流中的意义相同),且这条增广路的流量为x,那么这条增广路第i条边的花费就是x*wi,将x提出来,就可以得到整条增广路的花费就是,这i条边的单位花费之和*流量x。因为最大流是一定的了(因为要先保证找到的是最大流),那么只要这条增广路上的总的单位花费最小就可以了。这样就可以用spfa来跑最短路代替最大流中的dfs找增广路,这样就可以缩小费用了。其他的思路基本上与最大流相同,用增广路上的每条边减去这条路上的最小边,用其反边加上这条边。

      然后就是将总的花费记录下来,按照上面的思路,在用spfa找增广路时,会用一个dis数组来记录下从s(起点)开始到每个点的最短路,然后用dis[t(终点)]*x(流量),就可以得到这条增广路的花费,然后将其累加起来,就找到了总花费。最后print就可以了、、、、

      具体实现的时候还要考虑到找到增广路之后怎么对它在进行操作(也就是找最小流量和增流),可以在spfa的时候用一个faz数组记录下每个点最优方案下的父亲,然后再次遍历的时候就从t(终点)开始倒着找爸爸。

    一道例题:luogu3381

    代码:

    #include<queue>
    #include<cstring>
    #include<cstdio>
    #include<deque>
    #include<iostream>
    using namespace std;
    const int N=5010*2,M=50010*2;
    deque<int>q;
    struct node
    {
        int v,w,nxt,cost;
    }edg[M];
    int ejs,n,m,s,t,head[N],ans_cost,ans_w,dis[N],faz[N],map[N],inqu[N];
    void add(int u,int v,int w,int cost)
    {
        edg[++ejs].v=v;
        edg[ejs].w=w;
        edg[ejs].cost=cost;
        edg[ejs].nxt=head[u];
        head[u]=ejs;
    }
    int change(int x)
    {
        if(x%2) return x+1;
        return x-1;
    }
    bool spfa()
    {
        memset(faz,0,sizeof(faz));
        memset(inqu,0,sizeof(inqu));
        memset(dis,0x3f,sizeof(dis));
        memset(map,0,sizeof(map));
        while(!q.empty()) q.pop_front();
        q.push_back(s);
        dis[s]=0;
        inqu[s]=1;
        while(!q.empty())
        {
            int u=q.front();
            inqu[u]=0;
            q.pop_front();
            for(int i=head[u];i;i=edg[i].nxt)
            {
                int v=edg[i].v; 
                if(dis[v]>dis[u]+edg[i].cost&&edg[i].w>0)
                {
                    dis[v]=dis[u]+edg[i].cost;
                    faz[v]=u;
                    map[v]=i;
                    if(!inqu[v])
                    {
                        
                        if(!q.empty())
                        {
                            int k=q.front();
                            if(dis[v]<dis[k])
                            q.push_front(v);
                            else q.push_back(v); 
                        }
                        else q.push_back(v); 
                        inqu[v]=1; 
                    }
                }
            }
         }
         if(faz[t]) return 1;
         else return 0;
    }
    void work()
    {
        while(spfa())
        {
            int x=0x7fffffff,now=t;
            while(now!=s)
            {
                x=min(x,edg[map[now]].w);
                now=faz[now];
            }
            now=t;
            ans_w+=x;
            ans_cost+=dis[t]*x;
            while(now!=s)
            {
                edg[map[now]].w-=x;
                edg[change(map[now])].w+=x;    
                now=faz[now];
            }
        }
    }
    int main()
    {
        scanf("%d%d%d%d",&n,&m,&s,&t);
        for(int i=1,x,y,a,b;i<=m;++i)
        {
            scanf("%d%d%d%d",&x,&y,&a,&b);
            add(x,y,a,b);
            add(y,x,0,-b);
        }
        work();
        printf("%d %d",ans_w,ans_cost);
        return 0;
    }
    luogu3381

    PS:这个代码中用到了双端队列deque来优化spfa

  • 相关阅读:
    10.19NOIP模拟赛(DAY2)
    bzoj1880: [Sdoi2009]Elaxia的路线(spfa,拓扑排序最长路)
    P3469 [POI2008]BLO-Blockade(Tarjan 割点)
    P2746 [USACO5.3]校园网Network of Schools(Tarjan)
    10.17NOIP模拟赛
    10.16NOIP模拟赛
    P3953 逛公园(dp,最短路)
    牛客OI周赛2-提高组
    洛谷 P1948 [USACO08JAN]电话线Telephone Lines 题解
    洛谷 P2563 [AHOI2001]质数和分解 题解
  • 原文地址:https://www.cnblogs.com/wxyww/p/9325393.html
Copyright © 2011-2022 走看看