bzoj1061 [Noi2008]志愿者招募
Posted wfj_2048
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj1061 [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
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。
正解:不知道。。据说原本的正解线性规划被hack掉了。。
然而我连线性规划都不会,所以写了一个naive的费用流。。学了以后再来填坑吧。。
考虑从原点向第0天连容量为inf,费用为0的边,第i天向第i+1天连容量为inf-a[i],费用为0的边,我们把这条线称之为主线。第n天向汇点连容量为inf,费用为0的边。对于每一段区间,从第s-1天到第t天连容量为inf,费用为c的边,我们把这条线称为副线。那么跑费用流时,主线上的堵塞流就自动地转移到副线上,同时,副线又因为有费用,那么我们就可以算出最小的费用了。
//It is made by wfj_2048~ #include <algorithm> #include <iostream> #include <complex> #include <cstring> #include <cstdlib> #include <cstdio> #include <vector> #include <cmath> #include <queue> #include <stack> #include <map> #include <set> #define inf (1<<29) #define il inline #define RG register #define ll long long #define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout) using namespace std; struct edge{ int nt,to,flow,cap,cost; }g[30010]; queue <int> Q; int head[1010],dis[1010],flow[1010],fa[1010],p[1010],a[1010],n,m,S,T,num=1,cost; il int gi(){ RG int x=0,q=1; RG char ch=getchar(); while ((ch<‘0‘ || ch>‘9‘) && ch!=‘-‘) ch=getchar(); if (ch==‘-‘) q=-1,ch=getchar(); while (ch>=‘0‘ && ch<=‘9‘) x=x*10+ch-48,ch=getchar(); return q*x; } il void insert(RG int from,RG int to,RG int cap,RG int cost){ g[++num]=(edge){head[from],to,0,cap,cost},head[from]=num; } il int bfs(RG int S,RG int T){ for (RG int i=1;i<=n+3;++i) dis[i]=inf; Q.push(S),flow[S]=inf,dis[S]=0; while (!Q.empty()){ RG int x=Q.front(),v; Q.pop(); for (RG int i=head[x];i;i=g[i].nt){ v=g[i].to; if (dis[v]>dis[x]+g[i].cost && g[i].cap>g[i].flow){ flow[v]=min(flow[x],g[i].cap-g[i].flow); dis[v]=dis[x]+g[i].cost; fa[v]=x,p[v]=i,Q.push(v); } } } if (dis[T]==inf) return 0; cost+=flow[T]*dis[T]; for (RG int x=T;x!=S;x=fa[x]) g[p[x]].flow+=flow[T],g[p[x]^1].flow-=flow[T]; return 1; } il int mcmf(RG int S,RG int T){ cost=0; while (bfs(S,T)); return cost; } il void work(){ n=gi(),m=gi(); S=n+2,T=n+3; insert(S,1,inf,0),insert(1,S,0,0); for (RG int i=1;i<=n;++i) a[i]=gi(),insert(i,i+1,inf-a[i],0),insert(i+1,i,0,0); for (RG int i=1;i<=m;++i){ RG int s=gi(),t=gi(),c=gi(); insert(s,t+1,inf,c),insert(t+1,s,0,-c); } insert(n+1,T,inf,0),insert(T,n+1,0,0); printf("%d\n",mcmf(S,T)); return; } int main(){ File("volunteer"); work(); return 0; }
以上是关于bzoj1061 [Noi2008]志愿者招募的主要内容,如果未能解决你的问题,请参考以下文章
BZOJ 1061: [Noi2008]志愿者招募 [单纯形法]