费用流模版

基于贪心选择最小费用增广路增广的算法

Spfa费用流

struct E
{
    int to,next,cap,flow,cost;
}edge[maxm];
int head[maxn],tol;
inline void Addedge(int u,int v,int w,int c)
{
    edge[tol].to=v;edge[tol].cap=w;edge[tol].flow=0;edge[tol].cost=c;
    edge[tol].next=head[u];head[u]=tol++;
    edge[tol].to=u;edge[tol].cap=edge[tol].flow=0;edge[tol].cost=-c;
    edge[tol].next=head[v];head[v]=tol++;
    return;
}
struct Spfaflow
{
    int d[maxn],cur[maxn],s,t,n;
    bool vis[maxn];
    queue<int>Q;
    inline void init(){memset(head,-1,sizeof(head));tol=0;}
    inline bool spfa()
    {
        memset(d,0x3f,sizeof(int)*n);
        memset(vis,0,sizeof(bool)*n);
        d[s]=0;
        Q.push(s);
        while(!Q.empty()){
            int u=Q.front();Q.pop();
            vis[u]=0;
            for(int i=head[u];i!=-1;i=edge[i].next){
                int v=edge[i].to;
                if(edge[i].cap>edge[i].flow&&d[v]>d[u]+edge[i].cost){
                    d[v]=d[u]+edge[i].cost;
                    if(!vis[v]){
                        vis[v]=1;
                        Q.push(v);
                    }
                }
            }
        }
        return d[t]!=INF;
    }
    inline int dfs(int u,int a)
    {
        if(u==t) return a;
        int f=0;
        vis[u]=1;
        for(int &i=cur[u];i!=-1;i=edge[i].next){
            int v=edge[i].to;
            if(!vis[v]&&edge[i].cap>edge[i].flow&&d[v]==d[u]+edge[i].cost){
                int tmp=dfs(v,min(a,edge[i].cap-edge[i].flow));
                if(tmp){
                    edge[i].flow+=tmp;
                    edge[i^1].flow-=tmp;
                    f+=tmp;
                    a-=tmp;
                    if(!a) break;
                }
            }
        }
        return f;
    }
    inline int Maxflow(int s,int t,int n,int&cost)
    {
        this->s=s,this->t=t,this->n=n;
        int ans=0;
        while(spfa()){
            memcpy(cur,head,sizeof(int)*n);
            while(1){
                memset(vis,0,sizeof(bool)*n);
                int tmp=dfs(s,INF);
                if(!tmp) break;
                ans+=tmp;
                cost+=tmp*d[t];
            }
        }
        return ans;
    }
};

 Dijkstra费用流

给每个结点加一个势函数,变换边权为非负,每次更新势函数

struct E
{
    int to,next,cap,flow,cost;
}edge[maxm];
int head[maxn],tol;
inline void Addedge(int u,int v,int w,int c)
{
    edge[tol].to=v;edge[tol].cap=w;edge[tol].flow=0;edge[tol].cost=c;
    edge[tol].next=head[u];head[u]=tol++;
    edge[tol].to=u;edge[tol].cap=edge[tol].flow=0;edge[tol].cost=-c;
    edge[tol].next=head[v];head[v]=tol++;
    return;
}
struct Dijkstraflow
{
    struct Node
    {
        int u,d;
        Node(int x,int y):u(x),d(y){}
        bool operator<(const Node&P)const
        {
            return d>P.d;
        }
    };
    priority_queue<Node>Q;
    int d[maxn],h[maxn],pre[maxn],n;
    bool vis[maxn];
    inline void init(){memset(head,-1,sizeof(head));tol=0;}
    inline bool dijkstra(int s,int t)
    {
        memset(d,0x3f,sizeof(int)*n);
        memset(vis,0,sizeof(bool)*n);
        pre[s]=-1;
        Q.push(Node(s,d[s]=0));
        while(!Q.empty()){
            int u=Q.top().u;Q.pop();
            if(vis[u]) continue;
            vis[u]=1;
            for(int i=head[u];i!=-1;i=edge[i].next){
                int v=edge[i].to;
                if(!vis[v]&&edge[i].cap>edge[i].flow&&d[v]>d[u]+h[u]-h[v]+edge[i].cost){
                    pre[v]=i;
                    d[v]=d[u]+h[u]-h[v]+edge[i].cost;
                    Q.push(Node(v,d[v]));
                }
            }
        }
        return d[t]<INF;
    }
    inline int Maxflow(int s,int t,int n,int &cost)
    {
        this->n=n;
        int ans=0;
        memset(h,0,sizeof(int)*n);
        while(dijkstra(s,t)){
            int Min=INF;
            for(int i=pre[t];i!=-1;i=pre[edge[i^1].to]){
                if(Min>edge[i].cap-edge[i].flow){
                    Min=edge[i].cap-edge[i].flow;
                }
            }
            for(int i=pre[t];i!=-1;i=pre[edge[i^1].to]){
                edge[i].flow+=Min;
                edge[i^1].flow-=Min;
            }
            for(int i=0;i<n;i++) h[i]+=d[i];
            ans+=Min;
            cost+=Min*h[t];
        }
        return ans;
    }
};

时间复杂度:O(FElogV)

 

ZKW费用流

适用于流量大,费用小,增广路径短的图,每次至少增加一条可行边 

 

struct E
{
    int to,next,cap,flow,cost;
}edge[maxm];
int head[maxn],tol;
inline void Addedge(int u,int v,int w,int c)
{
    edge[tol].to=v;edge[tol].cap=w;edge[tol].flow=0;edge[tol].cost=c;
    edge[tol].next=head[u];head[u]=tol++;
    edge[tol].to=u;edge[tol].cap=edge[tol].flow=0;edge[tol].cost=-c;
    edge[tol].next=head[v];head[v]=tol++;
    return;
}
struct Zkwflow
{
    int d[maxn],cur[maxn],t,n;
    bool vis[maxn];
    inline void init(){memset(head,-1,sizeof(head));tol=0;}
    inline int dfs(int u,int a)
    {
        if(u==t) return a;
        vis[u]=1;
        for(int &i=cur[u];i!=-1;i=edge[i].next){
            int v=edge[i].to;
            if(!vis[v]&&edge[i].cap>edge[i].flow&&d[v]==d[u]+edge[i].cost){
                int tmp=dfs(v,min(a,edge[i].cap-edge[i].flow));
                if(tmp){
                    edge[i].flow+=tmp;
                    edge[i^1].flow-=tmp;
                    return tmp;
                }
            }
        }
        return 0;
    }
    inline bool mdf()
    {
        int Min=INF;
        for(int u=0;u<n;u++){
            if(!vis[u]) continue;
            for(int i=head[u];i!=-1;i=edge[i].next){
                int v=edge[i].to;
                if(edge[i].cap>edge[i].flow&&!vis[v]&&Min>d[u]-d[v]+edge[i].cost){
                    Min=d[u]-d[v]+edge[i].cost;
                }
            }
        }
        if(Min==INF) return 0;
        for(int i=0;i<n;i++){
            if(vis[i]) d[i]-=Min;
        }
        return 1;
    }
    inline int Maxflow(int s,int t,int n,int &cost)
    {
        this->t=t,this->n=n;
        memset(d,0,sizeof(int)*n);
        int ans=0;
        do{
            memcpy(cur,head,sizeof(int)*n);
            while(1){
                memset(vis,0,sizeof(bool)*n);
                int tmp=dfs(s,INF);
                if(!tmp) break;
                ans+=tmp;
                cost+=-d[s]*tmp;
            }
        }while(mdf());
        return ans;
    }
};

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值