[NOI2008] 志愿者招募 - 费用流

\(i\) 点表示第 \(i\)

志愿者 \((s_i,t_i,c_i)\),建边 \(s_i \to t_i +1\),费用 \(c_i\),流量无限

\(i\)\(i+1\) 连边 \(inf - a[i]\),费用为\(0\)

\(S \to 1, n+1 \to T\),费用为 \(0\),容量 \(inf\)

#include 
using namespace std;

#define int long long

namespace mcmf {
const int maxn = 50005;
const int maxm = 300005;
const int inf = 1e+9;
struct R {
    int to, nxt, co, va;
} e[maxm * 2 + 5];
int q[maxm + 5], l, r;
int vs[maxn + 5], nxt[maxn + 5], d[maxn + 5];
int h[maxn + 5], cnt = 1;
int n, m;
int ans;
void add(int u, int v, int w, int c) {
    cnt++;
    e[cnt] = (R){ v, h[u], w, c };
    h[u] = cnt;
    return;
}
int Spfa(int s, int t) {
    for (int i = 1; i <= n; i++) {
        nxt[i] = -1;
        d[i] = inf;
        vs[i] = 0;
    }
    l = r = 1;
    q[l] = s;
    d[s] = 0;
    vs[s] = 1;
    while (l <= r) {
        int u = q[l];
        l++;
        vs[u] = 0;
        for (int i = h[u]; i; i = e[i].nxt) {
            int v = e[i].to;
            int w = e[i].va;
            if (e[i].co && d[u] + w < d[v]) {
                nxt[v] = i;
                d[v] = d[u] + w;
                if (!vs[v]) {
                    q[++r] = v;
                    vs[v] = 1;
                }
            }
        }
    }
    if (d[t] < inf)
        return 1;
    return 0;
}
void Mco(int s, int t) {
    int flow = 0, cost = 0;
    while (Spfa(s, t)) {
        //cout<<"!";
        int mn = inf;
        for (int p = nxt[t]; p != -1; p = nxt[e[p ^ 1].to]) mn = min(e[p].co, mn);
        for (int p = nxt[t]; p != -1; p = nxt[e[p ^ 1].to]) {
            e[p].co -= mn;
            e[p ^ 1].co += mn;
        }
        flow += mn;
        cost += mn * d[t];
        //cout<<"?";
    }
    ans = cost;
    //cout<>n>>m;
    for(int i=1;i<=n;i++) cin>>a[i], mk(i,i+1,inf-a[i],0);
    mcmf::n = n+3;
    mk(n+2,1,inf,0);
    mk(n+1,n+3,inf,0);
    for(int i=1;i<=m;i++) {
        cin>>s[i]>>t[i]>>c[i];
        mk(s[i],t[i]+1,inf,c[i]);
    }
    mcmf::Mco(n+2,n+3);
    cout<

你可能感兴趣的:([NOI2008] 志愿者招募 - 费用流)