1061: [Noi2008]志愿者招募
Time Limit: 20 Sec Memory Limit: 162 MBSubmit: 4091 Solved: 2496
[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。
Source
无源汇最小费用可行流
原本无源汇的网络是这个样子的:
有$N+1$个点,代表每一天,其中有$N$条边连接,形如$<i,i+1,need_{i},inf,0>$,括号内分别为出点,入点,最小流量,最大流量,费用。这样就限制了每一天的志愿者人数最小值。
然后对于一类志愿者,如果设开始时间为$st$,终止时间为$ed$,费用为$ct$,那么连边$<ed+1,st,0,inf,ct>$,代表至少选0个这类志愿者(就是不选),至多inf(没有上限),选择一个费用为$ct$。
在这个网络上求解无源汇的最小费用可行流即可。
1 #include <cstdio> 2 #include <cstring> 3 4 inline char Char(void) 5 { 6 static const short siz = 1024; 7 8 static char buf[siz]; 9 static char *hd = buf + siz; 10 static char *tl = buf + siz; 11 12 if (hd == tl) 13 fread(hd = buf, 1, siz, stdin); 14 15 return *hd++; 16 } 17 18 inline int Int(void) 19 { 20 int ret = 0, neg = 0, c = Char(); 21 22 for (; c < 48; c = Char()) 23 if (c == '-')neg ^= true; 24 25 for (; c > 47; c = Char()) 26 ret = ret * 10 + c - '0'; 27 28 return neg ? -ret : ret; 29 } 30 31 const int mxn = 2005; 32 const int mxm = 20005; 33 const int siz = 2000005; 34 const int inf = 1000000007; 35 36 int n, m, need[mxn], st[mxm], ed[mxm], ct[mxm], cnt[mxn]; 37 38 int s, t; 39 int hd[siz]; 40 int to[siz]; 41 int fl[siz]; 42 int vl[siz]; 43 int nt[siz]; 44 45 inline void add(int u, int v, int f, int w) 46 { 47 static int tot = 0, init = 1; 48 49 if (init)memset(hd, -1, sizeof(hd)), init = 0; 50 51 nt[tot] = hd[u]; to[tot] = v; fl[tot] = f; vl[tot] = +w; hd[u] = tot++; 52 nt[tot] = hd[v]; to[tot] = u; fl[tot] = 0; vl[tot] = -w; hd[v] = tot++; 53 } 54 55 int pre[mxn]; 56 int dis[mxn]; 57 58 inline bool spfa(void) 59 { 60 static int que[siz]; 61 static int inq[mxn]; 62 static int head, tail; 63 64 for (int i = s; i <= t; ++i)dis[i] = inf; 65 memset(inq, 0, sizeof(inq)); 66 head = 0, tail = 0; 67 68 que[tail++] = s; 69 pre[s] = -1; 70 dis[s] = 0; 71 72 while (head != tail) 73 { 74 int u = que[head++], v; inq[u] = 0; 75 76 for (int i = hd[u]; ~i; i = nt[i]) 77 if (fl[i] && dis[v = to[i]] > dis[u] + vl[i]) 78 { 79 dis[v] = dis[u] + vl[i]; pre[v] = i ^ 1; 80 if (!inq[v])inq[que[tail++] = v] = 1; 81 } 82 } 83 84 return dis[t] < inf; 85 } 86 87 inline int minCost(void) 88 { 89 int cost = 0; 90 91 while (spfa()) 92 { 93 int flow = inf; 94 95 for (int i = pre[t]; ~i; i = pre[to[i]]) 96 if (flow > fl[i ^ 1])flow = fl[i ^ 1]; 97 98 for (int i = pre[t]; ~i; i = pre[to[i]]) 99 fl[i] += flow, fl[i ^ 1] -= flow; 100 101 cost += flow * dis[t]; 102 } 103 104 return cost; 105 } 106 107 signed main(void) 108 { 109 n = Int(); 110 m = Int(); 111 112 for (int i = 1; i <= n; ++i) 113 need[i] = Int(); 114 115 for (int i = 1; i <= m; ++i) 116 { 117 st[i] = Int(); 118 ed[i] = Int(); 119 ct[i] = Int(); 120 } 121 122 s = 0, t = n + 2; 123 124 for (int i = 1; i <= n; ++i) 125 { 126 add(i, i + 1, inf, 0); 127 128 cnt[i] -= need[i]; 129 cnt[i + 1] += need[i]; 130 } 131 132 for (int i = 1; i <= m; ++i) 133 add(ed[i] + 1, st[i], inf, ct[i]); 134 135 for (int i = 1; i <= n + 1; ++i) 136 if (cnt[i] < 0) 137 add(i, t, -cnt[i], 0); 138 else if (cnt[i] > 0) 139 add(s, i, +cnt[i], 0); 140 141 printf("%d ", minCost()); 142 }
@Author: YouSiki