• 网络流之费用流问题


    费用流即最小费用最大流

     白书粉书真是神器23333333

    先贴上粉书上的模板:

    struct Edge
    {
        int from,to,cap,flow,cost;        
        Edge(int u,int v,int c,int f,int w):
            from(u),to(v),cap(c),flow(f),cost(w)
            {}
    };
    
    int n,m;
    vector<Edge> edges;
    vector<int> G[maxn];
    int inq[maxn];
    int d[maxn];
    int p[maxn];
    int a[maxn];
    
    
    void init(int n)
    {
        //this->n=n;    粉书上原版有这一句,但明显会报错。感觉去掉也没什么影响...
        for (int i=0;i<n;i++)
            G[i].clear();
        edges.clear();
    }
    
    void AddEdge(int from,int to,int cap,int cost)
    {
        edges.push_back(Edge(from,to,cap,0,cost));
        edges.push_back(Edge(to,from,0,0,-cost));
        m=edges.size();
        G[from].push_back(m-2);
        G[to].push_back(m-1);
    }
    
    bool BellmanFord(int s,int t,int &flow,long long &cost)        //用队列优化过,感觉和SPFA一样了
    {
        for (int i=0;i<n;i++)   d[i]=INF;
        memset(inq,0,sizeof(inq));
        d[s]=0;     inq[s]=1;       p[s]=0;     a[s]=INF;
        
        queue<int> Q;
        Q.push(s);
        while (!Q.empty())
        {
            int u=Q.front();
            Q.pop();
            inq[u]=0;
            for (int i=0;i<G[u].size;i++)
            {
                Edge& e=edges[G[u][i]];
                if (e.cap>e.flow && d[e.to]>d[u]+e.cost())
                {
                    d[e.to]=d[u]+e.cost;
                    p[e.to]=G[u][i];
                    a[e.to]=min(a[u],e.cap-e.flow);
                    if (!inq[e.to])     
                    {
                        Q.push(e.to);
                        inq[e.to]=1;
                    }
                }
            }
        }
        if (d[t]==INF)      return false;
        flow+=a[t];
        cost+=(long long)d[t] * (long long)a[t];
        for (int u=t;u!=s;u=edges[p[u]].from)
        {
            edges[p[u]].flow+=a[t];
            edges[p[u]^1].flow-=a[t];
        }
        return true;
    }
        
    int MCMF(int s,int t,long long& cost)        //s:起点;t:汇点;
    {
        int flow=0;     cost=0;            //flow:求出来的最大流      cost:求出来的费用
        while (BellmanFord(s,t,flow,cost));
        return flow;
    }
    View Code

    Exercise:POJ2516

    #include <iostream>
    #include <cstring>
    #include <vector>
    #include <queue>
    using namespace std;
    #define INF 9999999
    
    struct Edge
    {
        int from,to,cap,flow,cost;
        Edge(int u,int v,int c,int f,int w):
            from(u),to(v),cap(c),flow(f),cost(w)
            {}
    };
    
    const int maxn=500;
    vector<Edge> edges;
    vector<int> G[maxn];
    int inq[maxn];
    int d[maxn];
    int p[maxn];
    int a[maxn];
    int flow,cost;
    int ne[60][60],me[60][60],ce[60][60][60];
    int tm,tn,tk,x,m,n,ans,sum;
    
    void init(int n)
    {
        //this->n=n;
        for (int i=0;i<n;i++)
            G[i].clear();
        edges.clear();
    }
    
    void AddEdge(int from,int to,int cap,int cost)
    {
        edges.push_back(Edge(from,to,cap,0,cost));
        edges.push_back(Edge(to,from,0,0,-cost));
        m=edges.size();
        G[from].push_back(m-2);
        G[to].push_back(m-1);
    }
    
    bool BellmanFord(int s,int t,int &flow,int &cost)
    {
        for (int i=0;i<n;i++)   d[i]=INF;
        memset(inq,0,sizeof(inq));
        d[s]=0;     inq[s]=1;       p[s]=0;     a[s]=INF;
    
        queue<int> Q;
        Q.push(s);
        while (!Q.empty())
        {
            int u=Q.front();
            Q.pop();
            inq[u]=0;
            for (int i=0;i<G[u].size();i++)
            {
                Edge& e=edges[G[u][i]];
                if ((e.cap>e.flow)&&(d[e.to]>d[u]+e.cost))
                {
                    d[e.to]=d[u]+e.cost;
                    p[e.to]=G[u][i];
                    a[e.to]=min(a[u],e.cap-e.flow);
                    if (!inq[e.to])
                    {
                        Q.push(e.to);
                        inq[e.to]=1;
                    }
                }
            }
        }
        if (d[t]==INF)      return false;
        flow+=a[t];
        cost+=d[t]*a[t];
        for (int u=t;u!=s;u=edges[p[u]].from)
        {
            edges[p[u]].flow+=a[t];
            edges[p[u]^1].flow-=a[t];
        }
        return true;
    }
    /*
    int MCMF(int s,int t,long long& cost)
    {
        flow=0;     cost=0;
        while (BellmanFord(s,t,flow,cost));
        return flow;
    }
    */
    int main()
    {
        while (cin>>tn>>tm>>tk)
        {
            if (tn==0&&tm==0&&tk==0)    break;    else
            {
                for (int i=1;i<=tn;i++)
                    for (int j=1;j<=tk;j++)
                        cin>>ne[i][j];           //[1..tn][1..k]        //ne[i][k]:shopkeeper-i需要的货物-k的数量
                for (int i=1;i<=tm;i++)
                    for (int j=1;j<=tk;j++)
                        cin>>me[i][j];           //[1..tm][1..k]        //me[i][k]:supply-i供应的货物-k的数量
                for (int x=1;x<=tk;x++)
                    for (int i=1;i<=tn;i++)
                        for (int j=1;j<=tm;j++)
                            cin>>ce[x][i][j];    //[1..k][1..tn][1..tm]     //ce[k][i][j]:对于货物-k,从supply-j运到shopkeeper-i的花费,对应图中m[j]点到n[i]点的每一条边
                ans=0;
    
                for (int x=1;x<=tk;x++)
                {
                    sum=0;
                    n=tn+tm+2;
                    init(n);
                    for (int i=1;i<=tm;i++)
                        for (int j=tm+1;j<=tm+tn;j++)
                            AddEdge(i,j,me[i][x],ce[x][j-tm][i]);
                    for (int i=1;i<=tm;i++)          AddEdge(0,i,me[i][x],0);            //AddEdge(0,i,INF,0);
                //连接超级起点的边:费用为0,流量为supply-i的供应量
                    for (int i=tm+1;i<=tm+tn;i++)    AddEdge(i,n-1,ne[i-tm][x],0);          //AddEdge(i,n-1,INF,0);
                //连接超级终点的边:费用为0,流量为shopkeeper-i的需求量
                //Reference:http://blog.csdn.net/lyy289065406/article/details/6742534
                //注意因为这里有限制:只要流量能满足shopkeeper需求即可,没必要追求最大。
                //所以不能把这些边的流量设成INF(无穷大)
                    flow=0;     cost=0;
                    while (BellmanFord(0,n-1,flow,cost));
                    for (int i=1;i<=tn;i++)     sum+=ne[i][x];
                    if (flow<sum)   ans=-1;
                    if (ans!=-1) ans+=cost;
                }
                cout<<ans<<endl;
            }
    
        }
    
    
        return 0;
    }
    View Code

    Reference:

    http://blog.csdn.net/swordholy/article/details/4558617

    http://blog.csdn.net/lyy289065406/article/details/6742534

    http://blog.csdn.net/ls_0222/article/details/6817077

    还有个神器叫zkw费用流,刷完二分图再看:

    http://www.artofproblemsolving.com/blog/54262

  • 相关阅读:
    【Java并发编程】之十一:线程间通信中notify通知的遗漏
    【Java并发编程】之十:使用wait/notify/notifyAll实现线程间通信的几点重要说明
    【Java并发编程】之九:死锁
    【Java并发编程】之八:多线程环境中安全使用集合API
    【Java并发编程】之七:使用synchronized获取互斥锁的几点说明
    多线程开发中遇到的问题
    Linux 设置IP,gate, 以及自动获取IP的方法
    C语言实现http get请求程序
    DHCP(动态主机配置协议)工作流程
    多线程程序中死锁的分析和解决方案
  • 原文地址:https://www.cnblogs.com/pdev/p/3876547.html
Copyright © 2020-2023  润新知