網絡流/費用流(洛谷 P3980 [NOI2008]志願者招募)

題目鏈接
想了許久,一看題解是一種比較sao的辦法.
1.源點連第一天
匯點連最後一天
容量爲INF費用爲0

2.然後每一天向後一天連一條容量爲INF-a[i]
費用爲0的邊

3.然後將每一類志願者s[i]與t[i]+1連一條容量爲
INF花費爲c[i]的邊
這樣爲了保證最大流是inf,圖會從3類邊中花費補流,最後最小費即爲所求.
下面是ac代碼:

#include <iostream>
#include <cstring>
#include <string>
#include <vector>
#include <queue>
#include <algorithm>
#include <cstdio>
#include <cmath>
#define ll long long
using namespace std;
#define ll long long
#define _min(x, y) ((x)>(y)?(y):(x))
#define pr(x, y) make_pair((x),(y))
const int M = 2e7;
const int N = 1e4;
const int inf = 0x3f3f3f3f;
int tot;
int mx, h[N], dis[N], pre[N];
int he[N], ne[M], ver[M], e[M], c[M];
void init(int n)
{
    mx = n;
    tot = 1;
}
void add(int x, int y, int w, int _c)
{
    ver[++tot] = y;
    ne[tot] = he[x];
    e[tot] = w;
    c[tot] = _c;
    he[x] = tot;

    ver[++tot] = x;
    ne[tot] = he[y];
    e[tot] = 0;
    c[tot] = -_c;
    he[y] = tot;
}
int EK(int s, int t, int f, int &flow)
{
    int res = 0;
    fill(h, h + 1 + mx, 0);
    while (f)
    {
        priority_queue <pair<int, int>, vector<pair<int, int> >, greater<pair<int, int> > >   q;
        fill(dis, dis + 1 + mx, inf);
        dis[s] = 0; q.push(pair<int, int>(0, s));
        while (q.size())
        {
            pair<int, int> now = q.top(); q.pop();
            int te = now.second;
            if (dis[te] < now.first)continue;
            for (int i = he[te]; i; i = ne[i])
            {
                if (e[i] > 0 && dis[ver[i]] > dis[te] + c[i] + h[te] - h[ver[i]])
                {
                    dis[ver[i]] = dis[te] + c[i] + h[te] - h[ver[i]];
                    pre[ver[i]] = i;
                    q.push(pair<int, int>(dis[ver[i]], ver[i]));
                }
            }
        }
        if (dis[t] == inf) break;
        for (int i = 0; i <= mx; ++i) h[i] += dis[i];
        int d = f;
        for (int i = pre[t]; i; i = pre[ver[i^1]]) d = min(d, e[i]);
        f -= d; flow += d; res += d*h[t];
        for (int i = pre[t]; i; i = pre[ver[i^1]])
        {
            e[i] -= d;
            e[i^1] += d;
        }
    }
    return res;
}
int main()
{
    int n, m;
    cin >> n >> m;
    int s = 0, t = n +2;
    init(t);
    for (int i = 1; i <= n; i++)
    {
        int te; scanf("%d", &te);
        add(i, i + 1, inf - te, 0);
    }
    add(s, 1, inf, 0);
    add(n+1, t, inf, 0);
    for (int i = 1; i <= m; i++)
    {
        int l, r, c;
        scanf("%d%d%d", &l, &r, &c);
        add(l, r+1, inf, c);
    }
    int flow = 0;
    int ans = EK(s, t, inf, flow);
    printf("%d\n", ans);
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章