当前位置: 首页 > news >正文

【题解】洛谷 P3980 [NOI2008] 志愿者招募 [最大流最小费用]

P3980 [NOI2008] 志愿者招募 - 洛谷 (luogu.com.cn)

0.思考

时间复杂度首先排除模拟,dp 也需要枚举,贪心没想到而且时空复杂度都不对(太少了)。

确定是要上算法的题,先总结下题意:

  • 有 n 天,第 i 天需要 a[i] 个志愿者
  • 志愿者可以覆盖连续区间 [s , t]
  • 目标是最小费用满足所有天的需求
  • 是一个覆盖问题,每个志愿者覆盖一个连续时间段

关键词:最小费用、多个需求、覆盖连续

单看前两个想到了网络流-最大流最小费用,我们把时间轴上的每一天离散当作节点,就有:

  • 节点 0:源点
  • 节点 1, 2, ..., n + 1:对应第 1, 2, ..., n + 1 天开始时
  • 节点 n + 2:汇点

这样每天志愿者数量的流动与需求就像是 “流” 一样。

1.进一步分析

同时我们有每个节点(除源汇节点)的的入流 = 出流,对应到题目中就有:

第 i - 1 天延续来的 + 第 i 天新招募的 = 第 i 天延续到 i + 1 天的 + 第 i 天结束工作的

那么第 i - 1 和第 i 天就应该有条边,第 i 天新招募的也应该引流到第 i 天。

第 i 天应该出流到第 i + 1 天,但第 i 天结束工作的不应该直接出流到第 i 天。

因为第 i 天结束工作的第 i 天开始时还在工作,所以应该出流到第 i + 1 天

至于覆盖问题,如果直接 s 为起点 t 为结束点的某种志愿者,从第 s 天连到第 t + 1 天。

这样就会跳过 s 到 t + 1 之间的节点,如何保证这些节点一定会被满足需求呢

考虑把第 i 天到第 i + 1 天的边流量设为 -a[i],这代表任何流量经过第 i 天都要减 a[i]费用为 0

负的边权不好处理,考虑天的边权都加上 INF,这样相互之间的大小关系不变,要求不变

(因为流量是无穷大的,所以真正在意的只有之间的大小关系)

这样在源点的冲流下,INF - a[i] 小的点(需求大的)会先被填平,流量变为 0。

这代表着这些点不能再被经过,需要绕路,也就是走 “志愿者边”

而以 s 为起点 t 为结束点的某种志愿者,从第 s 天连到第 t + 1 天,

流量为 INF,这代表可以选无数个志愿者,费用为 c。

这样保证了走 “志愿者边” 的情况都是需求大的天先走,走了就代表跳过流量为 0 的点。

再具体些,源点只连节点 1,汇点只连 n + 2。

第一遍走网络流时,由于 spfa 每一步都求最小费用,

会先将全部的天依次走一遍(所有费用为 0 的边)。

所有的边的流量都会减掉 \sum_{i=1}^{n}INF-max(a[i]),相当于需求最大的那天变为 0。

剩下的天变为与 max(a[i]) 的差值,差值越大代表着还有更多流量可以霍霍,更少用志愿者。

由于网络流-最大流最小费用的底层逻辑,需求较大的天会先变为 0,

天然的需要更多志愿者去填补它与别的天权值的差值,只有填补成一样的权值

才能和其他边共用志愿者(需求一样)

因为优先保证最大流,也就是所有点都被 “填平”,最大可流量是 INF(本来是 0 但之前加了)。

算法又会在其中选择最小费用的方法,求出最优答案。

2.代码

我用的是多次 spfa 判断残余网络里是否有增广路 + dinic 算法求最大流。

SPFA 时间复杂度 O(V + E),最多调用 N 次。

其中 V 是节点数量,本题中为天数 N

E 是边数,等于 (天数 + 志愿者种数 + 两条源汇边) * 2,2*(M+N+2)

也就是 O(V + E)=O(N+2*(N+M))=O(1e3+2*(1e4+1e3))

dinic 时间复杂度 O(E)=O(2*(N+M))=O(2*(1e4+1e3))

因为加了弧优化,单个回合每条边只会遍历一次。

总共时间复杂度 O(N(N+M)),可以通过。

注释代码:

#include<bits/stdc++.h>
using namespace std;typedef long long LL;
const int N = 1010;       // 点:0 ~ n+2 → 最多 1003
const int M = 3e4;     // 边:每条志愿者边 + 相邻天数 + 源汇边,*2 后约 22000
const LL INF = 2e9;int n, m;
LL a[N];struct edge {int x, y;LL c, f;    // 费用与可流量 int pre;
} e[M];
int elen, last[N], cur[N];  void ins(int x, int y, LL c, LL f) {   // 我流链式前向星 elen ++; e[elen] = {x, y, c, f, last[x]}; last[x] = elen;elen ++; e[elen] = {y, x, -c, 0, last[y]}; last[y] = elen;
}int st, ed;
LL mx_flow, mn_cost; 
LL d[N]; bool v[N];bool spfa() {queue<int> Q; Q.push(st);memset(d, 0x7f, sizeof(d)); LL inf = d[1];  d[st] = 0;memset(v, 0, sizeof(v)); v[st] = 1;while (!Q.empty()) {int x = Q.front(); Q.pop(); v[x] = 0;for (int k = last[x]; k; k = e[k].pre) if (e[k].f > 0) {int y = e[k].y;if (d[y] > d[x] + e[k].c) {d[y] = d[x] + e[k].c;if (!v[y]) {Q.push(y);v[y] = 1;}}}}return d[ed] != inf;   // 可以到达 ed,即还有增广流量路径 
}LL dinic(int x, LL f) {LL sx = 0; v[x] = 1;    // 当前点没有流量了,下次不要走 if (x == ed) {mn_cost += f * d[ed];return f;}for (int k = cur[x]; k; k = e[k].pre) if (e[k].f > 0) {int y = e[k].y;  cur[x] = k;   // 弧优化,这条边已经被走过了,同一回合不可能再有流量了if (d[y] == d[x] + e[k].c && !v[y]) {     // 如果 y 是 x 的下一层,且还有流量 LL sy = dinic(y, min(f - sx, e[k].f));sx += sy;e[k].f -= sy; e[k ^ 1].f += sy;if (sx == f) {    // 可用流量全部已走完 return f;}} }if (sx) {v[x] = 0;   // 还有可用流量,下次再来 }return sx;
}int main () {ios::sync_with_stdio(false);cin.tie(0);cin >> n >> m;elen = 1;    // 2 ^ 1 = 3, 3 ^ 1 = 2memset(last, 0, sizeof(last));st = 0; ed = n + 2;ins(st, 1, 0, INF);for (int i = 1; i <= n; i ++) {cin >> a[i];ins(i, i + 1, 0, INF - a[i]);}ins(n + 1, ed, 0, INF);for (int i = 1; i <= m; i ++) {int x, y; LL c;cin >> x >> y >> c;ins(x, y + 1, c, INF);}mx_flow = mn_cost = 0;memset (v, 0, sizeof(v));while (spfa()) {memcpy(cur, last, sizeof(last));mx_flow += dinic(st, 1ll << 60);    }cout << mn_cost << "\n";return 0; 
}

http://www.dtcms.com/a/569649.html

相关文章:

  • Fastapi服务在高并发情况下大量超时问题排查
  • 分类与回归算法(二) - 线性回归
  • 中国建设银行官网站企业企业信息网查询
  • [创业之路-709]:管理与经营的异同
  • 网站的数据库在哪里专业上海网站建设
  • 使用IOT-Tree Server通过S7 Eth协议连接西门子PLC S7-1200
  • 59网一起做网站如何把字体安装在wordpress
  • PostgreSQL 之上的开源时序数据库 TimescaleDB 详解
  • wordpress网站投放广告网站后台管理图片
  • 查询域名网站软文写作是什么意思
  • TCN-Transformer-GRU时间卷积神经网络结合编码器组合门控循环单元多特征分类预测Matlab实现
  • 类和对象(中):深入理解 C++ 类与对象:6 个默认成员函数核心解析
  • 中山哪里有做微网站的中国经济网
  • win11蓝屏笑脸提示重启怎么回事 蓝屏重启解决方法
  • 佰力博检测与你探讨压电薄膜介电/阻抗-频谱的应用领域有哪些
  • 长沙教育类网站建设好兄弟资源网
  • C++:哈希表的实现
  • 本地化部署后定制解决方案
  • Java中的WebSocket与实时通信!
  • SQL server创建数据表
  • MacOS-Terminal直接command解压缩文件文件夹
  • GIM 模型转 GLB 模型:从格式适配到前端渲染的完整方案
  • 什么是网站平台开发wordpress链接优化
  • 软件测试——自动化测试概念
  • 大模型-详解 Vision Transformer (ViT)
  • 建站公司互橙知乎郑州seo哪家专业
  • 09-ubuntu20.04 执行 apt update时报错,是因为官网已停止维护不再更新的缘故吗?
  • 南通做网站找谁求网站懂的说下开车
  • ps做网站宽度重庆公司团建推荐
  • uniapp中的uni_modules分包