网络流之费用流问题

费用流即最小费用最大流

 白书粉书真是神器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

原文地址:https://www.cnblogs.com/pdev/p/3876547.html