模板 - 最小费用最大流

SPFA版本:

#include<bits/stdc++.h>
using namespace std;


namespace SPFA_Mincost_Maxflow {
    const int MAXN=10000;
    const int MAXM=100000;
    const int INF=0x3f3f3f3f;

    struct Edge {
        int to,next,cap,flow,cost;
    } edge[MAXM];

    int head[MAXN],tol;

    int pre[MAXN],dis[MAXN];
    bool vis[MAXN];

    void init() {
        tol=0;
        memset(head,-1,sizeof(head));
    }

    void add_edge(int u,int v,int cap,int cost) {
        edge[tol].to=v;
        edge[tol].cap=cap;
        edge[tol].cost=cost;
        edge[tol].flow=0;
        edge[tol].next=head[u];
        head[u]=tol++;

        edge[tol].to=u;
        edge[tol].cap=0;
        edge[tol].cost=-cost;
        edge[tol].flow=0;
        edge[tol].next=head[v];
        head[v]=tol++;
    }

    bool spfa(int s,int t) {
        queue<int> q;
        memset(dis,INF,sizeof(dis));
        memset(vis,false,sizeof(vis));
        memset(pre,-1,sizeof(pre));

        dis[s]=0;
        vis[s]=true;
        q.push(s);
        while(!q.empty()) {
            int u=q.front();
            q.pop();
            vis[u]=false;
            for(int i=head[u]; i!=-1; i=edge[i].next) {
                int v=edge[i].to;
                if(edge[i].cap>edge[i].flow&&dis[v]>dis[u]+edge[i].cost) {
                    dis[v]=dis[u]+edge[i].cost;
                    pre[v]=i;
                    if(!vis[v]) {
                        vis[v]=true;
                        q.push(v);
                    }
                }
            }
        }
        if(pre[t]==-1)
            return false;
        else
            return true;
    }

    int mincost,maxflow;

    void mincost_maxflow(int s,int t) {
        int cost=0,flow=0;
        while(spfa(s,t)) {
            int tp=INF;
            for(int i=pre[t]; i!=-1; i=pre[edge[i^1].to]) {
                if(tp>edge[i].cap-edge[i].flow)
                    tp=edge[i].cap-edge[i].flow;
            }
            for(int i=pre[t]; i!=-1; i=pre[edge[i^1].to]) {
                edge[i].flow+=tp;
                edge[i^1].flow-=tp;
                cost+=edge[i].cost*tp;
            }
            flow+=tp;
        }
        mincost=cost;
        maxflow=flow;
        return;
    }

}


using namespace SPFA_Mincost_Maxflow;


int main() {
    int N,M,S,T;
    scanf("%d%d%d%d",&N,&M,&S,&T);
    init();

    while(M--) {
        int u,v,cap,cost;
        scanf("%d%d%d%d",&u,&v,&cap,&cost);
        add_edge(u,v,cap,cost);
    }

    mincost_maxflow(S,T);

    printf("%d %d\n",maxflow,mincost);
}

Dijkstra版本:

这个版本不容易被卡,据说会快70%。缺点是要控制负数费用不能负得太离谱,不然换 long long 试试吧。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;

const int maxn = 5000;
const int INF = 0x3f3f3f3f;

struct Edge {
    int to, cap, cost, flow;
    Edge() {}
    Edge(int to, int _cap, int _cost, int _flow) : to(to), cap(_cap), cost(_cost), flow(_flow) {}
};

struct MinCostMaxFlow {
    int V, H[maxn + 5], dis[maxn + 5], prev[maxn + 5], pree[maxn + 5];
    vector<Edge> G[maxn + 5];
    //调用前初始化
    void init(int n) {
        V = n;
        for(int i = 0; i <= V; ++i)
            G[i].clear();
    }
    //加边
    void addEdge(int from, int to, int cap, int cost) {
        G[from].push_back(Edge(to, cap, cost, G[to].size()));
        G[to].push_back(Edge(from, 0, -cost, G[from].size() - 1));
    }
    //flow是自己传进去的变量,就是最后的最大流,返回的是最小费用
    int minCostMaxFlow(int s, int t, int f, int& flow) {
        int cost = 0;
        fill(H, H + 1 + V, 0);
        while(f) {
            priority_queue <pii, vector<pii>, greater<pii> > q;
            fill(dis, dis + 1 + V, INF);
            dis[s] = 0;
            q.push(pii(0, s));
            while(!q.empty()) {
                pii now = q.top();
                q.pop();
                int v = now.second;
                if(dis[v] < now.first)
                    continue;
                for(int i = 0; i < G[v].size(); ++i) {
                    Edge& e = G[v][i];
                    if(e.cap > 0 && dis[e.to] > dis[v] + e.cost + H[v] - H[e.to]) {
                        dis[e.to] = dis[v] + e.cost + H[v] - H[e.to];
                        prev[e.to] = v;
                        pree[e.to] = i;
                        q.push(pii(dis[e.to], e.to));
                    }
                }
            }
            if(dis[t] == INF)
                break;
            for(int i = 0; i <= V; ++i)
                H[i] += dis[i];
            int d = f;
            for(int v = t; v != s; v = prev[v])
                d = min(d, G[prev[v]][pree[v]].cap);
            f -= d, flow += d, cost += d * H[t];
            for(int v = t; v != s; v = prev[v]) {
                Edge& e = G[prev[v]][pree[v]];
                e.cap -= d;
                G[v][e.flow].cap += d;
            }
        }
        return cost;
    }
} mcmf;

inline int read() {
    char ch = getchar();
    int x = 0;
    while(ch < '0' || ch > '9')
        ch = getchar();
    while(ch >= '0' && ch <= '9') {
        x = (x << 3) + (x << 1) + ch - '0';
        ch = getchar();
    }
    return x;
}

int a[2005];
int main() {
#ifdef Yinku
    freopen("Yinku.in", "r", stdin);
#endif // Yinku
    for(int T = read(); T; --T) {
        int n = read(), k = read();
        int s1 = 0, s2 = 2 * n + 1, t = 2 * n + 2;
        mcmf.init(2 * n + 2);
        mcmf.addEdge(s1, s2, k, 0);
        for(int i = 1; i <= n; ++i) {
            a[i] = read();
            mcmf.addEdge(i, i + n, 1, -a[i]);
            mcmf.addEdge(s2, i, 1, 0);
            mcmf.addEdge(i + n, t, 1, 0);
        }
        for(int i = 1; i <= n; ++i)
            for(int j = i + 1; j <= n; ++j)
                if(a[j] >= a[i])
                    mcmf.addEdge(i + n, j, 1, 0);
        int flow = 0;
        printf("%d\n", -mcmf.minCostMaxFlow(s1, t, INF, flow));
    }
}

转载于:https://www.cnblogs.com/Yinku/p/10706359.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值