学习笔记 --- 最小费用最大流

最小费用最大流,本人一只三种算法,MCMF、zkw(张昆玮)、Primal-Daul。然而基本没见人用过PD,多数都是MCMF和zkw。
对比起来,MCMF是基于spfa的一种算法,在稀疏图上十分高效;zkw算法是用spfa和KM重标号来进行计算的,在稠密图很高效,不过有一种图能够使zkw变慢:费用不小,容量不大,增广路比较长;

zkw最小费用最大流:

bool spfa()
{
    memset(mark,0,sizeof(mark));
    for (int i=S; i<=T; i++) dis[i]=-1;
    h=0,t=1;
    q[0]=T;mark[T]=1;dis[T]=0;
    while (h<t)
        {
            int now=q[h];h++;mark[now]=0;
            for (int i=head[now]; i; i=edge[i].next)
                if (edge[i^1].v && dis[now]+edge[i^1].c>dis[edge[i].to])
                    {   
                        dis[edge[i].to]=dis[now]+edge[i^1].c;
                        if (!mark[edge[i].to])
                            {
                                mark[edge[i].to]=1;
                                q[t++]=edge[i].to;
                            }
                    }
        }
    return dis[S]!=-1;
}

int dfs(int loc,int low)
{
    mark[loc]=1;
    if (loc==T) return low;
    int w,used=0;
    for (int i=head[loc]; i; i=edge[i].next)
        if (dis[edge[i].to]==dis[loc]-edge[i].c && edge[i].v && !mark[edge[i].to])
            {
                w=dfs(edge[i].to,min(low-used,edge[i].v));
                ans+=w*edge[i].c;
                edge[i].v-=w;edge[i^1].v+=w;
                used+=w;if (used==low)  return low;
            }
    return used;
}

void zkw()
{
    int tmp=0;
    while (spfa())
        {
            mark[T]=1;
            while (mark[T])
                {
                    memset(mark,0,sizeof(mark));
                    tmp+=dfs(S,inf);
                }
        }
}
---2016.03.16

浅谈线性规划类题目转费用流的建图方法:
首先添加松弛变量,将不等号都变为等号。分别用下一个式子减去上一个式子,如果每个变量只出现了两次且符号一正一负,那么可以转化为费用流。对于每个式子建立一个点,那么每个变量对应一条边,从一个点流出,向另一个点流入。这样,对于等式右边的常数 C,如果是正的,对应从源点向该点连一条流量 C,费用 0 的边;如果是负的对应从该点向汇点连一条流量 −C,费用 0 的边。对于每个变量,从它系数为正的式子向系数为负的式子连一条容量为inf,费用为它在目标函数里系数的边。这样网络流模型就构造完毕了。
详细例题可参考:http://blog.csdn.net/dad3zz/article/details/50815718

原文地址:https://www.cnblogs.com/DaD3zZ-Beyonder/p/5346223.html