1061: [Noi2008]志愿者招募
Time Limit: 20 Sec Memory Limit: 162 MB
Submit: 2660 Solved: 1658
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
招募第一类志愿者3名,第三类志愿者4名 30%的数据中,1 ≤ N, M ≤ 10,1 ≤ Ai ≤ 10; 100%的数据中,1 ≤ N ≤ 1000,1 ≤ M ≤ 10000,题目中其他所涉及的数据均 不超过2^31-1。
Source
解题:线性规划转费用流
https://www.byvoid.com/blog/noi-2008-employee/
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int INF = ~0u>>2; 4 const int maxn = 1010; 5 struct arc{ 6 int to,flow,cost,next; 7 arc(int x = 0,int y = 0,int z = 0,int nxt = -1){ 8 to = x; 9 flow = y; 10 cost = z; 11 next = nxt; 12 } 13 }e[maxn*maxn]; 14 int head[maxn],d[maxn],p[maxn],need[maxn],tot,S,T; 15 bool in[maxn]; 16 void add(int u,int v,int flow,int cost){ 17 e[tot] = arc(v,flow,cost,head[u]); 18 head[u] = tot++; 19 e[tot] = arc(u,0,-cost,head[v]); 20 head[v] = tot++; 21 } 22 bool spfa(){ 23 queue<int>q; 24 memset(d,0x3f,sizeof d); 25 memset(p,-1,sizeof p); 26 d[S] = 0; 27 q.push(S); 28 while(!q.empty()){ 29 int u = q.front(); 30 q.pop(); 31 in[u] = false; 32 for(int i = head[u]; ~i; i = e[i].next){ 33 if(e[i].flow && d[e[i].to] > d[u] + e[i].cost){ 34 d[e[i].to] = d[u] + e[i].cost; 35 p[e[i].to] = i; 36 if(!in[e[i].to]){ 37 in[e[i].to] = true; 38 q.push(e[i].to); 39 } 40 } 41 } 42 } 43 return p[T] > -1; 44 } 45 int solve(int ret = 0){ 46 while(spfa()){ 47 int minF = INF; 48 for(int i = p[T]; ~i; i = p[e[i^1].to]) 49 minF = min(minF,e[i].flow); 50 for(int i = p[T]; ~i; i = p[e[i^1].to]){ 51 e[i].flow -= minF; 52 e[i^1].flow += minF; 53 } 54 ret += d[T]*minF; 55 } 56 return ret; 57 } 58 int main(){ 59 int n,m,u,v,w; 60 memset(head,-1,sizeof head); 61 scanf("%d%d",&n,&m); 62 for(int i = 1; i <= n; ++i) 63 scanf("%d",need + i); 64 for(int i = tot = 0; i < m; ++i){ 65 scanf("%d%d%d",&u,&v,&w); 66 add(u,v + 1,INF,w); 67 } 68 S = 0; 69 T = n + 2; 70 for(int i = 1; i < T; ++i){ 71 if(i > 1) add(i, i - 1,INF,0); 72 int tmp = need[i] - need[i-1]; 73 if(tmp >= 0) add(S,i,tmp,0); 74 else if(tmp < 0) add(i,T,-tmp,0); 75 } 76 printf("%d ",solve()); 77 return 0; 78 }