969. 志愿者招募

题目链接

969. 志愿者招募

申奥成功后,布布经过不懈努力,终于成为奥组委下属公司人力资源部门的主管。

布布刚上任就遇到了一个难题:为即将启动的奥运新项目招募一批短期志愿者。

经过估算,这个项目需要 N 天才能完成,其中第 i 天至少需要 Ai 个人。

布布通过了解得知,一共有 M 类志愿者可以招募。

其中第 i 类可以从第 Si 天工作到第 Ti 天,招募费用是每人 Ci 元。

新官上任三把火,为了出色地完成自己的工作,布布希望用尽量少的费用招募足够的志愿者,但这并不是他的特长!

于是布布找到了你,希望你帮他设计一种最优的招募方案。

数据保证一定有解。

输入格式

第一行包含两个整数 N,M,表示完成项目的天数和可以招募的志愿者的种类。

接下来的一行中包含 N 个非负整数,表示每天至少需要的志愿者人数。

接下来的 M 行中每行包含三个整数 Si,Ti,Ci,含义如上文所述。

为了方便起见,我们可以认为每类志愿者的数量都是无限多的。

输出格式

包含一个整数,表示你所设计的最优方案的总费用。

数据范围

30 的数据中,1N,M101A_i10
100 的数据中,1N10001M10000
数据保证题目中其他所涉及的数据以及答案均不超过 2311

输入样例:

3 3 2 3 4 1 2 2 2 3 5 3 3 2

输出样例:

14

样例解释

招募 3 名第一类志愿者和 4 名第三类志愿者。

解题思路

费用流,上下界可行流

建图:对于 1n+1 的点,其中 i>i+1 的边当作第 i 天,每条边有上下界,即 [Ai,inf],每名工作者工作的时间为第 SiTi,费用为 Ci,对应建立的流网络中的节点即 SiTi+1,不妨从 Ti+1Si 两边,容量足够大,费用为 Ci,现在的流网络即无源汇上下界可行流,2188. 无源汇上下界可行流 给出了解决方法,即建立源点 s 和汇点 t,从 s 向所有 cc 为正的点连边,容量为 cc,费用为 0,从所有 cc 为正的点向 t 连边,容量为 cc,费用为 0,计算从 st 的最小费用最大流即为所求

  • 时间复杂度:O(k×(n+m)×f)

代码

// Problem: 志愿者招募 // Contest: AcWing // URL: https://www.acwing.com/problem/content/971/ // Memory Limit: 64 MB // Time Limit: 2000 ms // // Powered by CP Editor (https://cpeditor.org) // %%%Skyqwq #include <bits/stdc++.h> //#define int long long #define help {cin.tie(NULL); cout.tie(NULL);} #define pb push_back #define fi first #define se second #define mkp make_pair using namespace std; typedef long long LL; typedef pair<int, int> PII; typedef pair<LL, LL> PLL; template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; } template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; } template <typename T> void inline read(T &x) { int f = 1; x = 0; char s = getchar(); while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); } while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar(); x *= f; } const int N=1005,M=24005,inf=1e9; int n,m,S,T; int h[N],f[M],w[M],ne[M],e[M],idx; int d[N],incf[N],pre[N],q[N]; bool st[N]; void add(int a,int b,int c,int d) { e[idx]=b,f[idx]=c,w[idx]=d,ne[idx]=h[a],h[a]=idx++; e[idx]=a,f[idx]=0,w[idx]=-d,ne[idx]=h[b],h[b]=idx++; } bool spfa() { memset(d,0x3f,sizeof d); memset(incf,0,sizeof incf); d[S]=0,incf[S]=inf,q[0]=S; int hh=0,tt=1; while(hh!=tt) { int x=q[hh++]; if(hh==N)hh=0; st[x]=false; for(int i=h[x];~i;i=ne[i]) { int y=e[i]; if(d[y]>d[x]+w[i]&&f[i]) { d[y]=d[x]+w[i]; pre[y]=i; incf[y]=min(incf[x],f[i]); if(!st[y]) { q[tt++]=y; if(tt==N)tt=0; st[y]=true; } } } } return incf[T]>0; } int EK() { int cost=0; while(spfa()) { int t=incf[T]; cost+=t*d[T]; for(int i=T;i!=S;i=e[pre[i]^1]) f[pre[i]]-=t,f[pre[i]^1]+=t; } return cost; } int main() { memset(h,-1,sizeof h); scanf("%d%d",&n,&m); S=0,T=n+2; int lst=0; for(int i=1;i<=n;i++) { int c; scanf("%d",&c); lst-=c; if(lst<0)add(i,T,-lst,0); else if(lst>0) add(S,i,lst,0); add(i,i+1,inf-c,0); lst=c; } add(S,n+1,lst,0); for(int i=1;i<=m;i++) { int s,t,c; scanf("%d%d%d",&s,&t,&c); add(t+1,s,inf,c); } printf("%d",EK()); return 0; }

__EOF__

本文作者acwing_zyy
本文链接https://www.cnblogs.com/zyyun/p/16947090.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   zyy2001  阅读(18)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示

喜欢请打赏

扫描二维码打赏

支付宝打赏