2013-team4/code/min-cost-max-flow

从 Trac 迁移的文章

这是从旧校内 Wiki 迁移的文章,可能存在一些样式问题,您可以向 memset0 反馈。

原文章内容如下:

{{{
用spfa增广的费用流,这里费用的类型为double,流量的类型为int
图是用数组模拟链表搞的, cnt初始值为0
}}}
{{{
const int MAXN=105;
const int MAXM=50005;
const int inf=1000000000;
const double eps=1e-8;

struct node
{
    int u,v,f;
    double c;
    int next;
};

double dis[MAXN];
int pre[MAXN];
int head[MAXN];
bool vis[MAXN];
node e[MAXM];
int n,m,cnt;
int S,T;


void addedge(int u,int v,int f,double c)
{
    e[cnt].u=u; e[cnt].v=v; e[cnt].c=c; e[cnt].f=f; e[cnt].next=head[u]; head[u]=cnt++;
    e[cnt].u=v; e[cnt].v=u; e[cnt].c=-c; e[cnt].f=0; e[cnt].next=head[v]; head[v]=cnt++;
}

bool spfa()
{
    std::queue<int>q;
    while (!q.empty()) q.pop();
    for (int i=0; i<=T; i++)
    {
    dis[i]=inf; vis[i]=0; pre[i]=-1;
    }
    q.push(S); vis[S]=1; dis[S]=0;
    while (!q.empty())
    {
    int u=q.front(); q.pop();
    for (int now=head[u]; now!=-1; now=e[now].next)
    {
        int v=e[now].v;
        if (e[now].f>0&&dis[v]>dis[u]+e[now].c+eps)
        {
        dis[v]=dis[u]+e[now].c;
        pre[v]=now;
        if (!vis[v])
        {
            q.push(v);
            vis[v]=1;
        }
        }
    }
    vis[u]=false;
    }
    return (dis[T]<inf);
}

double MCMF()
{
    double mincost=0;
    int maxflow=0;
    while (spfa())
    {
    int nec=inf;
    for (int now=pre[T]; now!=-1; now=pre[e[now].u])
        nec=std::min(nec,e[now].f);
    mincost+=nec*dis[T];
    maxflow+=nec;
    for (int now=pre[T]; now!=-1; now=pre[e[now].u])
    {
        e[now].f-=nec;
        e[now^1].f+=nec;
    }
    }
    return mincost;
}
//优化spfa版本,如果上面的超时就用下面这个
const int MAXN=1010;
const int MAXM=25000;
const int inf=100000000;
struct node
{
    int v, next;
    int flow;
    int cost;
}E[MAXM*2];

bool vis[MAXN];
int head[MAXN], que[MAXN+1], dis[MAXN];
int N, M, S, T, cnt, ans;

void addedge(int u, int v, int a, int b, int c)
{
    E[cnt].v=v; E[cnt].flow=a; E[cnt].cost=c; E[cnt].next=head[u]; head[u]=cnt++;
    E[cnt].v=u; E[cnt].flow=b; E[cnt].cost=-c; E[cnt].next=head[v]; head[v]=cnt++;
}

int dfs(int u, int low)
{
    int ret=0, tmp;
    if (u==T) return low;
    vis[u]=true;
    for (int now=head[u]; now!=-1&&ret<low; now=E[now].next)
    {
        int v=E[now].v; if (vis[v]) continue;
        if (E[now].flow&&dis[v]==dis[u]+E[now].cost)
        {
            tmp=dfs(v, min(E[now].flow, low-ret));
            ans+=tmp*E[now].cost; ret+=tmp;
            E[now].flow-=tmp; E[now^1].flow+=tmp;
        }
    }
    return ret;
}

bool extend()
{
    for (int i=0; i<=N+1; i++) dis[i]=inf, vis[i]=false;
    dis[S]=0; vis[S]=true; que[0]=S;
    for (int front=0, rear=1; front!=rear; front=(front==MAXN)?0:front+1)
    {
        int u=que[front]; vis[u]=false;
        for (int now=head[u]; now!=-1; now=E[now].next)
        {
            int v=E[now].v, f=E[now].flow, c=E[now].cost;
            if (f>0&&dis[v]>dis[u]+c)
            {
                dis[v]=dis[u]+c;
                if (!vis[v])
                {
                    vis[v]=true;
                    que[rear]=v; rear=(rear==MAXN)?0:rear+1;
                }
            }
        }
    }
    if (dis[T]>=inf) return false;
    do
    {
        for (int i=0; i<=N+1; i++) vis[i]=false;
    }while (dfs(S, inf));
    return true;
}
}}}
{{{
最小费用最大流模板
执行 solve(s, t) 后,最大流保存在 flow 中,最小费用保存在 cost 中
}}}
{{{
const int MAXN = 2005;
const int INF = 2100000000;

struct Edge{
    int from, to, cap, flow, cost;
    Edge(int fr, int t, int c, int fl, int co){
        from = fr; to = t; cap = c; flow = fl; cost = co;
    }
};

struct MinCostMaxFlow{
    vector<Edge> E;
    vector<int> G[MAXN];
    int s, t;
    int flow, cost;
    void clear_graph(){
        E.clear();
        for(int i = 0; i < MAXN; i++) G[i].clear();
    }
    void clear_flow(){
        for(int i = 0; i < E.size(); i++)
            E[i].flow = 0;
    }
    void add_edge(int from, int to, int cap, int cost){
        int m = E.size();
        E.push_back(Edge(from, to, cap, 0, cost));
        E.push_back(Edge(to, from, 0, 0, -cost));
        G[from].push_back(m);
        G[to].push_back(m + 1);
    }
    void solve(int S, int T){
        s = S; t = T;
        queue<int> Q;
        bool inq[MAXN];
        int d[MAXN], pre[MAXN];
        flow = cost = 0;
        while(true){
            memset(inq, 0, sizeof(inq));
            for(int i = 0; i < MAXN; i++) d[i] = INF;
            d[s] = 0;
            Q.push(s);
            while(!Q.empty()){
                int x = Q.front(); Q.pop(); inq[x] = 0;
                for(int i = 0; i < G[x].size(); i++){
                    Edge& e = E[G[x][i]]; 
                    int y = e.to;
                    if(e.cap > e.flow && d[x] + e.cost < d[y]){
                        d[y] = d[x] + e.cost;
                        pre[y] = G[x][i];
                        if(!inq[y]){
                            inq[y] = true;
                            Q.push(y);
                        }
                    }
                }
            }
            if(d[t] == INF) break;
            int mi = INF;
            for(int x = t; x != s; x = E[pre[x]].from)
                mi = min(mi, E[pre[x]].cap - E[pre[x]].flow);
            for(int x = t; x != s; x = E[pre[x]].from){
                E[pre[x]].flow += mi;
                E[pre[x] ^ 1].flow -= mi;
            }
            flow += mi;
            cost += mi * d[t];
        }
    }
};
}}}
用spfa增广的费用流,这里费用的类型为double,流量的类型为int
图是用数组模拟链表搞的, cnt初始值为0
const int MAXN=105;
const int MAXM=50005;
const int inf=1000000000;
const double eps=1e-8;
struct node
{
    int u,v,f;
    double c;
    int next;
};
double dis[MAXN];
int pre[MAXN];
int head[MAXN];
bool vis[MAXN];
node e[MAXM];
int n,m,cnt;
int S,T;
void addedge(int u,int v,int f,double c)
{
    e[cnt].u=u; e[cnt].v=v; e[cnt].c=c; e[cnt].f=f; e[cnt].next=head[u]; head[u]=cnt++;
    e[cnt].u=v; e[cnt].v=u; e[cnt].c=-c; e[cnt].f=0; e[cnt].next=head[v]; head[v]=cnt++;
}
bool spfa()
{
    std::queue<int>q;
    while (!q.empty()) q.pop();
    for (int i=0; i<=T; i++)
    {
    dis[i]=inf; vis[i]=0; pre[i]=-1;
    }
    q.push(S); vis[S]=1; dis[S]=0;
    while (!q.empty())
    {
    int u=q.front(); q.pop();
    for (int now=head[u]; now!=-1; now=e[now].next)
    {
        int v=e[now].v;
        if (e[now].f>0&&dis[v]>dis[u]+e[now].c+eps)
        {
        dis[v]=dis[u]+e[now].c;
        pre[v]=now;
        if (!vis[v])
        {
            q.push(v);
            vis[v]=1;
        }
        }
    }
    vis[u]=false;
    }
    return (dis[T]<inf);
}
double MCMF()
{
    double mincost=0;
    int maxflow=0;
    while (spfa())
    {
    int nec=inf;
    for (int now=pre[T]; now!=-1; now=pre[e[now].u])
        nec=std::min(nec,e[now].f);
    mincost+=nec*dis[T];
    maxflow+=nec;
    for (int now=pre[T]; now!=-1; now=pre[e[now].u])
    {
        e[now].f-=nec;
        e[now^1].f+=nec;
    }
    }
    return mincost;
}
//优化spfa版本,如果上面的超时就用下面这个
const int MAXN=1010;
const int MAXM=25000;
const int inf=100000000;
struct node
{
    int v, next;
    int flow;
    int cost;
}E[MAXM*2];
bool vis[MAXN];
int head[MAXN], que[MAXN+1], dis[MAXN];
int N, M, S, T, cnt, ans;
void addedge(int u, int v, int a, int b, int c)
{
    E[cnt].v=v; E[cnt].flow=a; E[cnt].cost=c; E[cnt].next=head[u]; head[u]=cnt++;
    E[cnt].v=u; E[cnt].flow=b; E[cnt].cost=-c; E[cnt].next=head[v]; head[v]=cnt++;
}
int dfs(int u, int low)
{
    int ret=0, tmp;
    if (u==T) return low;
    vis[u]=true;
    for (int now=head[u]; now!=-1&&ret<low; now=E[now].next)
    {
        int v=E[now].v; if (vis[v]) continue;
        if (E[now].flow&&dis[v]==dis[u]+E[now].cost)
        {
            tmp=dfs(v, min(E[now].flow, low-ret));
            ans+=tmp*E[now].cost; ret+=tmp;
            E[now].flow-=tmp; E[now^1].flow+=tmp;
        }
    }
    return ret;
}
bool extend()
{
    for (int i=0; i<=N+1; i++) dis[i]=inf, vis[i]=false;
    dis[S]=0; vis[S]=true; que[0]=S;
    for (int front=0, rear=1; front!=rear; front=(front==MAXN)?0:front+1)
    {
        int u=que[front]; vis[u]=false;
        for (int now=head[u]; now!=-1; now=E[now].next)
        {
            int v=E[now].v, f=E[now].flow, c=E[now].cost;
            if (f>0&&dis[v]>dis[u]+c)
            {
                dis[v]=dis[u]+c;
                if (!vis[v])
                {
                    vis[v]=true;
                    que[rear]=v; rear=(rear==MAXN)?0:rear+1;
                }
            }
        }
    }
    if (dis[T]>=inf) return false;
    do
    {
        for (int i=0; i<=N+1; i++) vis[i]=false;
    }while (dfs(S, inf));
    return true;
}
最小费用最大流模板
执行 solve(s, t) 后,最大流保存在 flow 中,最小费用保存在 cost 中
const int MAXN = 2005;
const int INF = 2100000000;
struct Edge{
    int from, to, cap, flow, cost;
    Edge(int fr, int t, int c, int fl, int co){
        from = fr; to = t; cap = c; flow = fl; cost = co;
    }
};
struct MinCostMaxFlow{
    vector<Edge> E;
    vector<int> G[MAXN];
    int s, t;
    int flow, cost;
    void clear_graph(){
        E.clear();
        for(int i = 0; i < MAXN; i++) G[i].clear();
    }
    void clear_flow(){
        for(int i = 0; i < E.size(); i++)
            E[i].flow = 0;
    }
    void add_edge(int from, int to, int cap, int cost){
        int m = E.size();
        E.push_back(Edge(from, to, cap, 0, cost));
        E.push_back(Edge(to, from, 0, 0, -cost));
        G[from].push_back(m);
        G[to].push_back(m + 1);
    }
    void solve(int S, int T){
        s = S; t = T;
        queue<int> Q;
        bool inq[MAXN];
        int d[MAXN], pre[MAXN];
        flow = cost = 0;
        while(true){
            memset(inq, 0, sizeof(inq));
            for(int i = 0; i < MAXN; i++) d[i] = INF;
            d[s] = 0;
            Q.push(s);
            while(!Q.empty()){
                int x = Q.front(); Q.pop(); inq[x] = 0;
                for(int i = 0; i < G[x].size(); i++){
                    Edge& e = E[G[x][i]]; 
                    int y = e.to;
                    if(e.cap > e.flow && d[x] + e.cost < d[y]){
                        d[y] = d[x] + e.cost;
                        pre[y] = G[x][i];
                        if(!inq[y]){
                            inq[y] = true;
                            Q.push(y);
                        }
                    }
                }
            }
            if(d[t] == INF) break;
            int mi = INF;
            for(int x = t; x != s; x = E[pre[x]].from)
                mi = min(mi, E[pre[x]].cap - E[pre[x]].flow);
            for(int x = t; x != s; x = E[pre[x]].from){
                E[pre[x]].flow += mi;
                E[pre[x] ^ 1].flow -= mi;
            }
            flow += mi;
            cost += mi * d[t];
        }
    }
};