网络流--最小费用最大流 (理解)

1、什么是最小费用最大流问题

  上篇文章我们讲解了最大流问题,那什么是最小费用最大流呢?听名字就可以看出,我们要在满足最大流的同时找到达成最大流的最小费用。

对于一个网络流,最大流是一定的,但是组成最大流的费用是可以不同的,这里就有了在最大流网络上产生的费用流网络,就有了最小花费问题。

  简单来说,就是满足最大流的路径可能有多条,我们要从这多条路径中找到一条花费代价最小的路径。所以最大流是解决这类问题的前提

2、EK算法 + SPFA 最短路

    我们用每条边单位流量的花费作为边权,假如一条合法路径上每条边的花费分别为 c1,c2,.......ck , 并且这条边上的最小流量为flow,

  那么这条路径上的花费为 : c1 * flow + c2*flow + ..... + ck*flow = (c1+ c2 + c3 + .... + ck)*flow =  dis [ci] * flow

  这里的 dis[ci] 就是我们要求的最短路!

3、算法思想

  采用贪心的思想,每次找到一条从源点到达汇点的路径,增加流量,且该条路径满足使得增加的流量的花费最小,直到无法找到一条从源点到达汇点的路径,算法结束。

由于最大流量有限,每执行一次循环流量都会增加,因此该算法肯定会结束,且同时流量也必定会达到网络的最大流量;同时由于每次都是增加的最小的花 费,即当前的最小花费是所有到达当前流量flow时的花费最小值,因此最后的总花费最小。

4、求解步骤

  1、找到一条从源点到达汇点的花费最小的路径,该花费 = 使用该路径上的边的单位费用之和
  2、然后找出这条路径上的边的容量的最小值f,则当前最大流 max_flow 扩充f(求最大流的过程,同时当前最小费用 min_cost 扩充 f*min_dist(s,t)
  3、更新路径流量 flow[][] ,将这条路径上的每条正向边的容量都减少f,每条反向边的容量都增加f。
  4、重复(1~3)直到无法找到从源点到达汇点的路径。

5、需要注意几点

  1、注意超级源点和超级终点的建立。这里的超级源点/汇点的建立是把所有边统一起来,构成一张网络图,因为有些题目不会直接给你网络图,

  需要你自己去建立,例如 hdu 1533

  2、初始化时,正向边的单位流量费用为cost[u][v],那么反向边的单位流量费用就为 -cost[u][v]。正向边和反向边的费用互为相反数,因为回流费用减少。
  3、费用cost数组和容量cap数组每次都要初始化为0。
  4、求解从源点到汇点的“最短”路径时,由于网络中存在负权边,因此使用SPFA来实现。

6、代码

  

int cap[500][500],cost[500][500],flow[500][500];//cap是容量,cost是花费,flow是流量
int pre[500],dis[500],vis[500],cnt[500];//pre是记录增广路的前驱节点,dis[i]是记录源点到节点i的最小距离
//vis[i]标记点是否在队列中,cnt[i]记录点i进入队列的次数

int n,m;
int st,endd;
int mn_cost,mx_flow;
int spfa()
{
    for(int i=0;i<n;i++)
        dis[i]=mx;
    memset(vis,0,sizeof(vis));
    memset(cnt,0,sizeof(cnt));

    queue<int>p;
    p.push(st);//st是起点
    vis[st]=1;
    cnt[st]=1;
    dis[st]=0;
    while(!p.empty())
    {
        int now=p.front();
        p.pop();
        vis[now]=0;
        for(int i=0;i<n;i++)
        {
            if(cap[now][i]>flow[now][i]&&dis[i]>dis[now]+cost[now][i])//这里将费用看成是长度,求源点到汇点的最小距离
            {
                dis[i]=dis[now]+cost[now][i];
                pre[i]=now;
                if(vis[i]==0)
                {
                    p.push(i);
                    vis[i]=1;
                    cnt[i]++;
                    if(cnt[i]>n)
                        return 0;
                }
            }
        }
    }
    if(dis[endd]>=mx)
        return 0;
    return 1;
}
void bfs(int n)//顶点数
{
    memset(flow,0,sizeof(flow));
    mx_flow=0;
    mn_cost=0;
    while(spfa())
    {
        int f=mx;
        for(int i=endd;i!=st;i=pre[i])
            f=min(f,cap[pre[i]][i]-flow[pre[i]][i]);

        for(int i=endd;i!=st;i=pre[i])
        {
            flow[pre[i]][i]+=f;
            flow[i][pre[i]]-=f;
        }
        mn_cost+=dis[endd]*f;             mx_flow+=f;

    }
}

模板题:https://www.cnblogs.com/-citywall123/p/11329609.html

原文地址:https://www.cnblogs.com/-citywall123/p/11329508.html

时间: 2024-08-30 00:11:11

网络流--最小费用最大流 (理解)的相关文章

网络流(最小费用最大流):POJ 2135 Farm Tour

Farm Tour Time Limit: 1000ms Memory Limit: 65536KB This problem will be judged on PKU. Original ID: 2135 64-bit integer IO format: %lld      Java class name: Main When FJ's friends visit him on the farm, he likes to show them around. His farm compris

网络流--最小费用最大流MUMF模板

标准大白书式模板 1 #include<stdio.h> //大概这么多头文件昂 2 #include<string.h> 3 #include<vector> 4 #include<queue> 5 #include<algorithm> 6 using namespace std; 7 const int maxm=10000+100; //最大点数 8 const int INF=0x3f3f3f3f; 9 10 struct edge{

网络流最小费用最大流建图些许方法

无向图的情况 加边的时候直接加两条边即可,因为这个dinic算法是可以判重边 poj 3469 代码 最小流 流量确定的时候 添加两个源点和汇点 前两个源点相连,汇点相连,容量为确定的流量 poj 2135 代码 poj 3686 代码 多源多汇 添加一个源点和汇点 把源点和每一个之前的相连 容量为1 把汇点和每一个之前的相连 容量为1 poj 3281 代码 poj 2195 代码 版权声明:都是兄弟,请随意转载,请注明兄弟是谁

网络流——最小费用最大流模板

#zkw费用流# 参考网址: https://artofproblemsolving.com/community/c1368h1020435 zkw大佬的改进:①在dfs的时候可以实现多路增广②KM算法节省SPFA时间(然而我这里没有KM,要问为什么,当然是因为我不会了orz): but,参考了另外的博客,修修补补又三年~ 1 #include <algorithm> 2 #include <iostream> 3 #include <cstring> 4 #inclu

LiberOJ #6013. 「网络流 24 题」负载平衡 最小费用最大流 供应平衡问题

#6013. 「网络流 24 题」负载平衡 内存限制:256 MiB时间限制:1000 ms标准输入输出 题目类型:传统评测方式:文本比较 上传者: 匿名 提交提交记录统计讨论测试数据 题目描述 G 公司有 n nn 个沿铁路运输线环形排列的仓库,每个仓库存储的货物数量不等.如何用最少搬运量可以使 n nn 个仓库的库存数量相同.搬运货物时,只能在相邻的仓库之间搬运. 输入格式 文件的第 1 11 行中有 1 11 个正整数 n nn,表示有 n nn 个仓库.第 2 22 行中有 n nn 个

【网络流24题】餐巾计划问题(最小费用最大流)

[网络流24题]餐巾计划问题(最小费用最大流) 题面 COGS 洛谷上的数据范围更大,而且要开longlong 题解 餐巾的来源分为两种: ①新买的 ②旧的拿去洗 所以,两种情况分别建图 先考虑第一种 因为新买餐巾没有任何限制,并且随时可以买 所以直接从源点向每一天连边,容量为INF,费用为餐巾的价格 因为流要流出去,所以每个点向汇点连边,容量为每天的用量,费用为0 第二种,旧的拿去洗 首先考虑一下怎么算有多少旧的餐巾 每天用旧的餐巾的数量值一定的,不可能变多 因此从源点向这些点连边,容量为每天

CGOS461 [网络流24题] 餐巾(最小费用最大流)

题目这么说的: 一个餐厅在相继的N天里,第i天需要Ri块餐巾(i=l,2,…,N).餐厅可以从三种途径获得餐巾. 购买新的餐巾,每块需p分: 把用过的餐巾送到快洗部,洗一块需m天,费用需f分(f<p).如m=l时,第一天送到快洗部的餐巾第二天就可以使用了,送慢洗的情况也如此. 把餐巾送到慢洗部,洗一块需n天(n>m),费用需s分(s<f). 在每天结束时,餐厅必须决定多少块用过的餐巾送到快洗部,多少块送慢洗部.在每天开始时,餐厅必须决定是否购买新餐巾及多少,使洗好的和新购的餐巾之和满足当

【BZOJ-3876】支线剧情 有上下界的网络流(有下界有源有汇最小费用最大流)

3876: [Ahoi2014]支线剧情 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 821  Solved: 502[Submit][Status][Discuss] Description [故事背景] 宅男JYY非常喜欢玩RPG游戏,比如仙剑,轩辕剑等等.不过JYY喜欢的并不是战斗场景,而是类似电视剧一般的充满恩怨情仇的剧情.这些游戏往往 都有很多的支线剧情,现在JYY想花费最少的时间看完所有的支线剧情. [问题描述] JYY现在所玩的R

【COGS 461】[网络流24题] 餐巾 最小费用最大流

既然是最小费用最大流我们就用最大流来限制其一定能把每天跑满,那么把每个表示天的点向T连流量为其所需餐巾,费用为0的边,然后又与每天的餐巾对于买是无限制的因此从S向每个表示天的点连流量为INF,费用为一个餐巾的费用的边,然后我们考虑怎么用旧餐巾,我们用旧餐巾,要既不影响本点流量,也不影响本点费用,因此我们在开一坨点表示其对应得那天的旧餐巾,并通过他向离他快洗和离他慢洗天数的天的点连边,流量为Inf,费用为快洗.慢洗的费用,然后对于多余的旧餐巾,我们在一排天点中间从第一天连续地连到最后一天,流量为I