Luogu P2656采蘑菇(Tarjan + spfa)

采蘑菇

题目描述

小胖和 ZYR 要去 ESQMS 森林采蘑菇。

ESQMS 森林间有 N 个小树丛,M 条小径,每条小径都是单向的,连接两个小树丛,上面都有一定数量的蘑菇。小胖和 ZYR 经过某条小径一次,可以采走这条路上所有的蘑菇。由于 ESQMS 森林是一片神奇的沃土,所以一条路上的蘑菇被采过后,又会长出一些新的蘑菇,数量为原来蘑菇的数量乘上这条路的“恢复系数”,再下取整。

比如,一条路上有 4 个蘑菇,这条路的“恢复系数”为 0.7,则第一~四次经过这条路径所能采到的蘑菇数量分别为 4,2,1,0

现在,小胖和 ZYR 从 S 号小树丛出发,求他们最多能采到多少蘑菇。

思路

由于每一条边都是可以重复经过得,所以考虑找到一个环使得将环内所有得蘑菇都采集完后,再进入下一个环,这样得采集方式可以使得最后得答案最大。那么这些环上得点可以缩成一个点,让这个环上所有得贡献都变成缩点后得点权。将所有得联通分量缩点之后,就是一个有向无环得图,这样就可以考虑从起点 S 出发求得到达每一个点得最大贡献是多少从而确定最后得答案,也就是在 DAG 上用 spfa 跑一遍最长路。

std::cin.tie(nullptr)->sync_with_stdio(false); int n, m; std::cin >> n >> m; std::vector<std::array<int, 3>> G[n + 1]; for (int i = 1; i <= m; i++) { int u, v, w; double k; std::cin >> u >> v >> w >> k; G[u].push_back({v, w, k * 10}); } std::vector<int> dfn(n + 1), stk(n + 1), low(n + 1); std::vector<int> scc(n + 1); std::vector<bool> vis(n + 1); int idx = 0, top = 0, cnt = 0; // idx是时间戳,top是栈的指针,cnt是强连通分量的数量->缩点的个数 std::function<void(int)> tarjan = [&] (int u) -> void { dfn[u] = low[u] = ++ idx; stk[++top] = u; vis[u] = true; for (auto& [v, w, k] : G[u]) { if (!dfn[v]) { tarjan(v); low[u] = std::min(low[u], low[v]); } else if (vis[v]) { low[u] = std::min(low[u], dfn[v]); } } if (dfn[u] == low[u]) {//时间戳和回溯点是同一个那就是缩点 int v = 0; cnt++; do { v = stk[top--]; vis[v] = false; scc[v] = cnt; } while(v != u); } }; for (int i = 1; i <= n; i++) { if (!dfn[i]) tarjan(i); } std::vector<std::array<int, 2>> adj[cnt + 1]; std::vector<int> sum(cnt + 1); for (int i = 1; i <= n; i++) { for (auto& [v, w, k] : G[i]) { if (scc[i] == scc[v]) { while(w) sum[scc[i]] += w, w = w * k / 10; } else { adj[scc[i]].push_back({scc[v], w}); } } } int s; std::cin >> s; s = scc[s]; std::queue<int> q; q.push(s); std::vector<int> dist(cnt + 1, -1); std::vector<bool> st(cnt + 1); st[s] = true; dist[s] = sum[s]; while(!q.empty()) { int u = q.front(); q.pop(); st[u] = false; for (auto& [v, w] : adj[u]) { if (dist[v] < dist[u] + w + sum[v]) { dist[v] = dist[u] + w + sum[v]; if (!st[v]) { st[v] = true; q.push(v); } } } } std::cout << *max_element(all(dist)) << "\n"; return 0 ^ 0;

__EOF__

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