【NOI2008】志愿者招募
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
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
NOI,数学 ,网络流 ,线性规划
思路{
填坑的网络流。
将天数连边,容量INF-Ai,费用0;
志愿者从Si向Ti连边,容量INF,费用Ci,用这些边填坑
虚拟源,汇点S,T,S连1,容量INF,T连n+1,容量INF,费用均为0;
最小费用最大流即可。
证明{
源汇点容量为INF,保证最大流为INF
天数之间的容量上限,故需要志愿者的边填补。
又根据增广路的性质,可知一定能够满足条件。
这也是为什么容量为INF-Ai的原因。
}
}
1 #include<algorithm> 2 #include<iostream> 3 #include<cstring> 4 #include<cstdio> 5 #include<vector> 6 #include<queue> 7 #include<ctime> 8 #include<cmath> 9 #include<map> 10 #include<set> 11 #define MAXX 11003 12 #define INF 99999999 13 using namespace std; 14 struct edge{ 15 int nxt,to,c,w; 16 }e[MAXX*4]; 17 int head[MAXX],pre[MAXX],dis[MAXX],in[MAXX],n,m,x,cc,tt,ss,ans,tot; 18 void add(int from,int to,int c,int w){ 19 e[tot].nxt=head[from]; 20 e[tot].to=to; 21 e[tot].w=w; 22 e[tot].c=c; 23 head[from]=tot++; 24 } 25 void ADD(int from,int to,int c,int w){ 26 add(from,to,c,w); 27 add(to,from,0,-w); 28 } 29 bool SPFA(int s,int t){ 30 queue<int>que; 31 while(!que.empty())que.pop(); 32 for(int i=1;i<=n+3;++i)dis[i]=INF,in[i]=false; 33 que.push(s);in[s]=true;dis[s]=0; 34 while(!que.empty()){ 35 int u=que.front(); 36 for(int i=head[u];i!=-1;i=e[i].nxt) 37 if(e[i].c>0&&dis[e[i].to]>dis[u]+e[i].w){ 38 int v=e[i].to; 39 dis[v]=dis[u]+e[i].w; 40 pre[v]=i; 41 if(!in[v])in[v]=true,que.push(v); 42 } 43 in[u]=false; 44 que.pop(); 45 }if(dis[t]==INF)return false; 46 int u,p,sum=INF; 47 for(u=t;u!=s;u=e[p^1].to) 48 p=pre[u],sum=min(sum,e[p].c); 49 for(u=t;u!=s;u=e[p^1].to){ 50 p=pre[u]; 51 e[p].c-=sum,e[p^1].c+=sum; 52 ans+=sum*e[p].w; 53 }return true; 54 } 55 int mincostflow(int s,int t){ 56 while(SPFA(s,t)); 57 return ans; 58 } 59 int main(){ 60 memset(head,-1,sizeof(head)); 61 scanf("%d%d",&n,&m); 62 for(int i=1;i<=n;++i) 63 if(i!=1&&i!=n){ 64 scanf("%d",&x); 65 ADD(i,i+1,INF-x,0); 66 }else if(i==1){int x; 67 scanf("%d",&x); 68 ADD(0,1,INF,0); 69 ADD(1,2,INF-x,0); 70 }else { 71 scanf("%d",&x); 72 ADD(n,n+1,INF-x,0); 73 ADD(n+1,n+2,INF,0); 74 } 75 for(int i=1;i<=m;++i){ 76 scanf("%d%d%d",&ss,&tt,&cc); 77 ADD(ss,tt+1,INF,cc); 78 } 79 printf("%d",mincostflow(0,n+2)); 80 return 0; 81 }