首页 > 代码库 > 【NOI2008】志愿者招募

【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,数学 ,网络流 ,线性规划

 

<style>p { margin-bottom: 0.25cm; line-height: 120% }</style>

思路{

  填坑的网络流。

  将天数连边,容量INF-Ai,费用0

  志愿者从SiTi连边,容量INF,费用Ci,用这些边填坑

  虚拟源,汇点STS1,容量INFTn+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 }

 

天数之间的容量上限,故需要志愿者的边填补。

    又根据增广路的性质,可知一定能够满足条件。

    这也是为什么容量为INF-Ai的原因。

   }

}

 

【NOI2008】志愿者招募