zoukankan      html  css  js  c++  java
  • 费用流

    最小费用最大流spfa做法

    1.以费用为边权,求源到汇的最短路径
    2.从最短路径上找到剩余流量最小的边
    3.把整条路径上的边的流量都减少那么多,并更新费用
    4.重复做1-3,直到找不到从源到汇的路径。

    Slf优化:每次入队时候把这个点的费用与队首的点的费用相比较,如果比那个点的费用小,插到队头,否则插到队尾。
    这个优化对于普通的最短路问题同样有优化,对于没有负权边的图优化尤其大。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    using namespace std;
    struct data{
    int to,cap,cost,next;
    }g[80001];
    int h[2101],d[2101],k=1,used[201],que[100000],head,tail,last[2101],ans=0;
    int INF;
    inline int read(){ 
        int x; bool f; char c; 
        for (f=0; (c=getchar())<'0'||c>'9'; f=c=='-'); 
        for (x=c-'0'; (c=getchar())>='0'&&c<='9'; x=(x<<3)+(x<<1)+c-'0'); 
        return f?-x:x; 
    } 
    void add(int from,int to,int cap,int cost)
    {
        g[++k].next=h[from];h[from]=k;g[k].to=to;g[k].cap=cap;g[k].cost=cost;
        g[++k].next=h[to];h[to]=k;g[k].to=from;g[k].cap=0;g[k].cost=-cost;
    }
    bool spfa(int s,int t)
    {
        memset(last,0,sizeof(last));
        memset(d,127/3,sizeof(d));INF=d[0];
        memset(used,0,sizeof(used));
        head=tail=50000;que[tail++]=s;used[s]=1;d[s]=0;
        while(head<=tail)
        {
            int u=que[head++];
            for(int i=h[u];i;i=g[i].next)
            {
                if(g[i].cap&&d[u]+g[i].cost<d[g[i].to])
                {
                d[g[i].to]=d[u]+g[i].cost;last[g[i].to]=i;
                if(!used[g[i].to])
                    {
                        if(d[g[i].to]<d[que[head]])que[--head]=g[i].to;
                        else que[tail++]=g[i].to;used[g[i].to]=1;
                    }
                }
            }
            used[u]=0;
        }
        if(d[t]==INF)return false;
        return true;
    }
    void mcf(int t)
    {
        int minn=INF;
        for(int i=last[t];i;i=last[g[i^1].to])minn=min(minn,g[i].cap);
        for(int i=last[t];i;i=last[g[i^1].to])
        {
            ans+=g[i].cost*minn;
            g[i].cap-=minn;g[i^1].cap+=minn;
        }
    }
    while(spfa(1,n))mcf(n);

     费用流的原始对偶(Primal-Dual)算法

    1我们每次都先从汇点走反边往回用spfa求一次最短路

    2对于一条边<i,j>,如果其在最短路上,设j更靠近T,则一定满足d[i]-cost[i][j]==d[j],我们就可以判断<i,j>是否在最短路上,如果是,就沿着这条路增广

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    int inq[100000],d[100000],h[100000],q[200000],from[100000],head,tail,k=1,INF=999999999,ans=0,used[100000];
    struct data{
        int to,cap,cost,next;
    }g[1000000];
    void add(int from,int to,int cap,int cost)
    {
        g[++k].next=h[from];h[from]=k;g[k].to=to;g[k].cap=cap;g[k].cost=cost;
        g[++k].next=h[to];h[to]=k;g[k].to=from;g[k].cap=0;g[k].cost=-cost;
    }
    bool spfa(int s,int t)
    {
        head=tail=100000;
        memset(d,127/3,sizeof(d));INF=d[0];
        memset(inq,0,sizeof(inq));
        q[tail++]=t;d[t]=0;inq[t]=1;
        while(head<=tail) 
        {
            int u=q[head++];inq[u]=0;
            for(int i=h[u];i;i=g[i].next)
            {
                if(g[i^1].cap&&d[u]+g[i^1].cost<d[g[i].to])
                {
                    d[g[i].to]=d[u]+g[i^1].cost;
                    if(!inq[g[i].to])
                    {
                        if(d[g[i].to]<d[q[head]])q[--head]=g[i].to;
                        else q[tail++]=g[i].to;inq[g[i].to]=1;
                    }
                }
            }
        }
        return d[s]!=INF;
     } 
    int dfs(int u,int t,int f)
    {
        used[u]=1;
        if(u==t)return f;
        int _used=0,w;
        for(int i=h[u];i;i=g[i].next)
        {
            if(!used[g[i].to]&&g[i].cap&&d[u]-g[i].cost==d[g[i].to])
            {
                w=dfs(g[i].to,t,min(g[i].cap,f-_used));
                if(w)
                {
                    _used+=w;g[i].cap-=w;g[i^1].cap+=w;ans+=w*g[i].cost;
                    if(_used==f)return f;
                }
            }
        }
        return _used;
    }
    void PD(int s,int t)
    {
        while(spfa(s,t))
        {
            used[t]=1;
            while(used[t])
            {
                memset(used,0,sizeof(used));
                dfs(s,t,INF);
            }
        }
    }
  • 相关阅读:
    三个心态做人做学问 沧海
    成功走职场要找准自己的"快捷键" 沧海
    免费离线下载 拂晓风起
    Hibernate 获取某个表全部记录时 奇怪现象 (重复出现某个记录) 拂晓风起
    无法读取mdb 如果连接不了ACCESS mdb文件,就尝试安装MDAC 拂晓风起
    Netbeans 使用 Hibernate 逆向工程 生成hbm和pojo 拂晓风起
    如何点击单选框 radio 后面的文字,选中单选框 拂晓风起
    Java 连接access 使用access文件 不用配置 拂晓风起
    mysql下如何执行sql脚本 拂晓风起
    Hibernate配置access Hibernate 连接 access 拂晓风起
  • 原文地址:https://www.cnblogs.com/lher/p/6580941.html
Copyright © 2011-2022 走看看