最小费用最大流模板

20 篇文章 0 订阅
6 篇文章 0 订阅

最小增广路算法

/*
最小费用最大流算法
注释部分是当固定流量K,则在增广时当flow+a>=k时只增广k-flow单位
亦可连一条新汇点到原汇点容量为k,费用为0的边
*/
struct Edge{
    int from, to, cap, flow, cost;
    Edge(int a, int b, int c, int d, int e) : from(a), to(b), cap(c), flow(d), cost(e){}
};
int k;
struct MCMF{
int n, m, s, t;
vector<Edge> edges;
VI G[maxn];
bool vis[maxn];
int d[maxn], p[maxn], a[maxn];

void init(int n)
{
    this-> n = n;
    REP(i, n + 1)
        G[i].clear();
    edges.clear();
}

void add(int from, int to, int cap, int cost)
{
    Edge e(from, to, cap, 0, cost);
    edges.PB(e);
    Edge e2(to, from, 0, 0, -cost);
    edges.PB(e2);
    int sz = edges.size();
    G[from].PB(sz - 2);
    G[to].PB(sz - 1);
}

bool spfa(int s, int t, int& flow, int& cost)
{
    queue<int> Q;
    CLR(vis, false);
    REP(i, n + 1)
        d[i] = INF;
    d[s] = 0, vis[s] = 1,p[s] = 0, a[s] = INF;
    Q.push(s);
    while (!Q.empty())
    {
        int u = Q.front(); Q.pop();
        vis[u] = 0;
        REP(i, SZ(G[u]))
        {
            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 (!vis[e.to])
                {
                    Q.push(e.to);
                    vis[e.to] = 1;
                }
            }
        }
    }
    if (d[t] == INF)    return false;
//    if (flow + a[t] >= k)
//        a[t] = k - flow;
    flow += a[t];
    cost += d[t] * a[t];
//    if (a[t] == 0)  return 0;
    int u = t;
    while (u != s)
    {
        edges[p[u]].flow += a[t];
        edges[p[u] ^ 1].flow -= a[t];
        u = edges[p[u]].from;
    }
    return true;
}

int mincost(int s, int t)
{
    int flow = 0, cost = 0;
    while (spfa(s, t, flow, cost));
//        if (flow >= k)
//            break;
    if (flow < k)   return -1;
    return cost;
}}mcmf;


int main()
{
    int u, v, a, c;
    int n, m;
    while (~RIII(n, m, k))
    {
        mcmf.init(n);
        REP(i, m)
        {
            RIV(u, v, a, c);
            FE(j, 1, c)
                mcmf.add(u, v, 1, (2 * j - 1) * a);
        }
        WI(mcmf.mincost(1, n));
    }
}


ZKW费用流

struct ZKW_flow{  
    int st, ed, ecnt, n;  
    int head[MAXN];  
    int cap[MAXE], cost[MAXE], to[MAXE], next[MAXE], dis[MAXN]; ;  
  
    void init(){  
        memset(head, 0, sizeof(head));  
        ecnt = 2;  
    }  
  
    void addEdge(int u, int v, int cc, int ww){  
        cap[ecnt] = cc; cost[ecnt] = ww; to[ecnt] = v;  
        next[ecnt] = head[u]; head[u] = ecnt++;  
        cap[ecnt] = 0; cost[ecnt] = -ww; to[ecnt] = u;  
        next[ecnt] = head[v]; head[v] = ecnt++;  
    }  
  
    void SPFA(){  
        for(int i = 1; i <= n; ++i) dis[i] = INF;  
        priority_queue<pair<int, int> > Q;  
        dis[st] = 0;  
        Q.push(make_pair(0, st));  
        while(!Q.empty()){  
            int u = Q.top().second, d = -Q.top().first;  
            Q.pop();  
            if(dis[u] != d) continue;  
            for(int p = head[u]; p; p = next[p]){  
                int &v = to[p];  
                if(cap[p] && dis[v] > d + cost[p]){  
                    dis[v] = d + cost[p];  
                    Q.push(make_pair(-dis[v], v));  
                }  
            }  
        }  
        for(int i = 1; i <= n; ++i) dis[i] = dis[ed] - dis[i];  
    }  
  
    int minCost, maxFlow;  
    bool use[MAXN];  
  
    int add_flow(int u, int flow){  
        if(u == ed){  
            maxFlow += flow;  
            minCost += dis[st] * flow;  
            return flow;  
        }  
        use[u] = true;  
        int now = flow;  
        for(int p = head[u]; p; p = next[p]){  
            int &v = to[p];  
            if(cap[p] && !use[v] && dis[u] == dis[v] + cost[p]){  
                int tmp = add_flow(v, min(now, cap[p]));  
                cap[p] -= tmp;  
                cap[p^1] += tmp;  
                now -= tmp;  
                if(!now) break;  
            }  
        }  
        return flow - now;  
    }  
  
    bool modify_label(){  
        int d = INF;  
        for(int u = 1; u <= n; ++u) if(use[u])  
            for(int p = head[u]; p; p = next[p]){  
                int &v = to[p];  
                if(cap[p] && !use[v]) d = min(d, dis[v] + cost[p] - dis[u]);  
            }  
        if(d == INF) return false;  
        for(int i = 1; i <= n; ++i) if(use[i]) dis[i] += d;  
        return true;  
    }  
  
    int min_cost_flow(int ss, int tt, int nn){  
        st = ss, ed = tt, n = nn;  
        minCost = maxFlow = 0;  
        SPFA();  
        while(true){  
            while(true){  
                for(int i = 1; i <= n; ++i) use[i] = 0;  
                if(!add_flow(st, INF)) break;  
            }  
            if(!modify_label()) break;  
        }  
        return minCost;  
    }  
};  


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值