费用流处理负圈的方法

正常,我们的最小费用流的费用都应该是正数。
但是,有时,边权会出现负数,进而可能出现负圈。
这时,我们可以这样处理:
在每次增广时,先在整张图中找负圈,若能找到,则沿着负圈增广。
否则,再找增广路进行增广。
找负圈使用dfs的spfa会更好写,更快。
代码:

bool dfs(int u)
{
    bk[u]=true;
    for(int i=fr[u];i!=-1;i=ne[i])
    {
        if(w[i]>0&&jl[u]+fy[i]<jl[v[i]])
        {
            jl[v[i]]=jl[u]+fy[i];
            la[v[i]]=u;lb[v[i]]=i;
            if(bk[v[i]])
            {
                fq=v[i];
                return true;
            }
            if(dfs(v[i]))
                return true;
        }
    }
    bk[u]=false;
    return false;
}
bool spfa()
{
    for(int i=1;i<=N;i++)
    {
        bk[i]=false;
        jl[i]=inf;
    }
    for(int i=1;i<=N;i++)
    {
        fq=-1;
        if(dfs(i))
            return true;
    }
    for(int i=1;i<=N;i++)
    {
        bk[i]=false;
        jl[i]=inf;
    }
    jl[S]=0;fq=-1;
    dfs(S);
    return jl[T]<inf;
}
int feiyl(int &fei)
{
    int he=0;fei=0;
    while(spfa())
    {
        if(fq==-1)
        {
            int u=T,zx=inf;
            while(u!=S)
            {
                if(w[lb[u]]<zx)
                    zx=w[lb[u]];
                u=la[u];
            }
            he+=zx;fei+=jl[T]*zx;u=T;
            while(u!=S)
            {
                w[lb[u]]-=zx;
                w[lb[u]^1]+=zx;
                u=la[u];
            }
        }
        else
        {
            int u=fq,zx=inf;
            while(1)
            {
                if(w[lb[u]]<zx)
                    zx=w[lb[u]];
                u=la[u];
                if(u==fq)break;
            }u=fq;
            while(1)
            {
                w[lb[u]]-=zx;
                w[lb[u]^1]+=zx;
                fei+=zx*fy[lb[u]];
                u=la[u];
                if(u==fq)break;
            }
        }
    }
    return he;
}

猜你喜欢

转载自www.cnblogs.com/lnzwz/p/12327725.html