[BZOJ1061]志願者招募

題目鏈接BZOJ1061

題目大意
題目講的清楚簡潔,這裏就不講了(其實是因爲我不知道該怎麼複述

題解推薦感謝BYVoid的超強題解

分析
上面的題解講得很清楚,這裏具體講一下怎麼建圖。
1. 將所有項移到左邊之後,設正項爲流入,負項爲流出。
2. 觀察發現,對於第i 種自願者,其在第S[i] 個等式出現正項,第T[i]+1 項出現負項;對於Y[i] ,其在第i 項出現負項,第i+1 項出現正項。
3. 所以T[i]+1S[i] 連邊,容量爲INF ,費用爲V[i]ii+1 連邊,容量爲INF ,費用爲0
4. 對於常數項,若爲正值,由S 向其連邊,容量爲絕對值;反之,其向T 連邊,容量爲絕對值。

上代碼

#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int N = 1e3 + 10;
const int M = 15e3 + 10;
const int INF = 0x3f3f3f3f;

int n, m, S, T;

int head[N], len = 2;
struct nodeLib {
    int to, nxt, flow, cost;
    inline void add(int a, int b, int c, int d) {
        to = b, flow = c, cost = d;
        nxt = head[a], head[a] = len++;
    }
} lib[M << 1];

inline int read() {
    int ans = 0;
    char ch = getchar();
    while (ch < '0' || ch > '9') ch = getchar();
    while (ch >= '0' && ch <= '9')
        ans = ans * 10 + ch - '0', ch = getchar();
    return ans;
}

int ps[M];
inline void makePath(int a, int b, int c, int d) {
    lib[len].add(a, b, c, d);
    lib[len].add(b, a, 0, -d);
}
void init() {
    n = read(), m = read();
    S = 0, T = n + 2;
    for (int i = 1; i <= n; i++) ps[i] = read();
    for (int i = n + 1; i >= 1; i--) {
        ps[i] -= ps[i - 1];
        if (ps[i] > 0) makePath(i, T, ps[i], 0);
        else if (ps[i] < 0) makePath(S, i, -ps[i], 0);
    }
    for (int i = 1; i <= m; i++) {
        int a = read(), b = read(), c = read();
        makePath(b + 1, a, INF, c);
    }
    for (int i = 1; i <= n; i++)
        makePath(i, i + 1, INF, 0);
}

queue <int> Q;
bool inQ[N];
int dist[N], preE[N], preV[N];
bool SPFA() {
    memset(dist, 0x3f, sizeof(dist));
    dist[S] = 0, inQ[S] = true, Q.push(S);
    while (!Q.empty()) {
        int tmp = Q.front();
        Q.pop(), inQ[tmp] = false;
        for (int p = head[tmp]; p; p = lib[p].nxt) {
            int now = lib[p].to;
            if (lib[p].flow && dist[now] > dist[tmp] + lib[p].cost) {
                dist[now] = dist[tmp] + lib[p].cost;
                preV[now] = tmp, preE[now] = p;
                if (!inQ[now]) inQ[now] = true, Q.push(now);
            }
        }
    }
    return dist[T] != INF;
}
int MCMF() {
    int ans = 0;
    while (SPFA()) {
        int maxf = INF;
        for (int p = T; p != S; p = preV[p])
            maxf = min(maxf, lib[preE[p]].flow);
        for (int p = T; p != S; p = preV[p])
            lib[preE[p]].flow -= maxf, lib[preE[p] ^ 1].flow += maxf;
        ans += dist[T] * maxf;
    }
    return ans;
}

int main() {
    init();
    printf("%d\n", MCMF());
    return 0;
}

以上

發佈了33 篇原創文章 · 獲贊 2 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章