[BZOJ1061][Noi2008]志愿者招募
1061: [Noi2008]志愿者招募
Time Limit: 20 Sec Memory Limit: 162 MB Submit: 5017 Solved: 2989 [Submit][Status][Discuss]Description
申奥成功后,布布经过不懈努力,终于成为奥组委下属公司人力资源部门的主管。布布刚上任就遇到了一个难
题:为即将启动的奥运新项目招募一批短期志愿者。经过估算,这个项目需要N 天才能完成,其中第i 天至少需要
Ai 个人。 布布通过了解得知,一共有M 类志愿者可以招募。其中第i 类可以从第Si 天工作到第Ti 天,招募费用
是每人Ci 元。新官上任三把火,为了出色地完成自己的工作,布布希望用尽量少的费用招募足够的志愿者,但这
并不是他的特长!于是布布找到了你,希望你帮他设计一种最优的招募方案。
Input
第一行包含两个整数N, M,表示完成项目的天数和可以招募的志愿者的种类。 接下来的一行中包含N 个非负
整数,表示每天至少需要的志愿者人数。 接下来的M 行中每行包含三个整数Si, Ti, Ci,含义如上文所述。为了
方便起见,我们可以认为每类志愿者的数量都是无限多的。
Output
仅包含一个整数,表示你所设计的最优方案的总费用。
Sample Input
3 3
2 3 4
1 2 2
2 3 5
3 3 2
2 3 4
1 2 2
2 3 5
3 3 2
Sample Output
14
HINT
1 ≤ N ≤ 1000,1 ≤ M ≤ 10000,题目中其他所涉及的数据均 不超过2^31-1。
byvoid已经讲得很清楚了,点这里
#include <cstdio> inline int readint(){ int f = 1, n = 0; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar(); } while(ch <= '9' && ch >= '0'){ n = (n << 1) + (n << 3) + ch - '0'; ch = getchar(); } return f * n; } const int maxn = 1000 + 10, maxm = 10000 + 10, INF = 0x3f3f3f3f; struct Edge{ int to, cap, cost, next; Edge(){} Edge(int _t, int _w, int _c, int _n): to(_t), cap(_w), cost(_c), next(_n){} }e[maxm << 2]; int fir[maxn] = {0}, cnt = 1; inline void ins(int u, int v, int w, int c){ e[++cnt] = Edge(v, w, c, fir[u]); fir[u] = cnt; e[++cnt] = Edge(u, 0, -c, fir[v]); fir[v] = cnt; } int num[maxn] = {0}; int sour, sink; bool inq[maxn] = {false}; int dis[maxn]; int q[maxn], head, tail; int pre[maxn]; bool SPFA(){ for(int i = sour; i <= sink; i++){ dis[i] = INF; inq[i] = false; pre[i] = 0; } head = tail = 0; dis[sour] = 0; inq[sour] = true; q[tail++] = sour; int u, v; while(head != tail){ u = q[head++]; if(head == 1010) head = 0; inq[u] = false; for(int i = fir[u]; i; i = e[i].next){ v = e[i].to; if(e[i].cap && dis[v] > dis[u] + e[i].cost){ dis[v] = dis[u] + e[i].cost; pre[v] = i; if(!inq[v]){ inq[v] = true; q[tail++] = v; if(tail == 1010) tail = 0; } } } } return dis[sink] != INF; } void MCMF(){ int flow, cost = 0; while(SPFA()){ flow = INF; for(int i = pre[sink]; i; i = pre[e[i ^ 1].to]) if(e[i].cap < flow) flow = e[i].cap; for(int i = pre[sink]; i; i = pre[e[i ^ 1].to]){ e[i].cap -= flow; e[i ^ 1].cap += flow; } cost += flow * dis[sink]; } printf("%d\n", cost); } int main(){ int n, m; n = readint(); m = readint(); for(int i = 1; i <= n; i++) num[i] = readint(); for(int a, b, c, i = 1; i <= m; i++){ a = readint(); b = readint(); c = readint(); ins(a, b + 1, INF, c); } sour = 0; sink = n + 2; for(int t, i = 1; i <= n + 1; i++){ t = num[i] - num[i - 1]; if(t >= 0) ins(sour, i, t, 0); else ins(i, sink, -t, 0); if(i) ins(i, i - 1, INF, 0); } MCMF(); return 0; }