洛谷 P2656 采蘑菇-普及+/提高
题目描述
小胖和 ZYR 要去 ESQMS 森林采蘑菇。
ESQMS 森林间有 NNN 个小树丛,MMM 条小径,每条小径都是单向的,连接两个小树丛,上面都有一定数量的蘑菇。小胖和 ZYR 经过某条小径一次,可以采走这条路上所有的蘑菇。由于 ESQMS 森林是一片神奇的沃土,所以一条路上的蘑菇被采过后,又会长出一些新的蘑菇,数量为原来蘑菇的数量乘上这条路的“恢复系数”,再下取整。
比如,一条路上有 444 个蘑菇,这条路的“恢复系数”为 0.70.70.7,则第一~四次经过这条路径所能采到的蘑菇数量分别为 4,2,1,04,2,1,04,2,1,0。
现在,小胖和 ZYR 从 SSS 号小树丛出发,求他们最多能采到多少蘑菇。
输入格式
第一行两个整数,NNN 和 MMM。
第二行到第 M+1M+1M+1 行,每行四个数,分别表示一条小路的起点,终点,初始蘑菇数,恢复系数。
第 M+2M+2M+2 行,一个整数 SSS。
输出格式
一行一个整数,表示最多能采到多少蘑菇,保证答案不超过 (231−1)(2^{31}-1)(231−1)。
输入输出样例 #1
输入 #1
3 3
1 2 4 0.5
1 3 7 0.1
2 3 4 0.6
1
输出 #1
8
说明/提示
对于 30%30\%30% 的数据,N≤7N\le 7N≤7,M≤15M\le15M≤15
另有 30%30\%30% 的数据,满足所有“恢复系数”为 000。
对于 100%100\%100% 的数据,1≤N≤8×1041 \le N\le 8\times 10^41≤N≤8×104,1≤M≤2×1051\le M\le 2\times 10^51≤M≤2×105,0≤恢复系数≤0.80\le\text{恢复系数}\le 0.80≤恢复系数≤0.8 且最多有一位小数, 1≤S≤N1\le S\le N1≤S≤N。
solution
- 思路:对于有环的地方,必能将所有蘑菇采到,先将所有的环缩成一个点,然后开始 dp
- 1 用 tarjan 算法找到所有边双连通分量,将其中所有的边中权重综合起来,包括次生的权重 (即再生的蘑菇)
- 2 用 dp 计算 DAG 的最大值
代码
#include "cstring"
#include "string"
#include "algorithm"
#include "iostream"
#include "vector"
#include "unordered_set"
#include "unordered_map"
#include "bitset"
#include "set"using namespace std;/** 思路:对于有环的地方,必能将所有蘑菇采到,先将所有的环缩成一个点,然后开始 dp* 1 用 tarjan 算法找到所有边双连通分量,将其中所有的边中权重综合起来,包括次生的权重* 2 用 dp 计算 DAG 的最大值*/const int N = 8e4 + 5;
typedef long long ll;int n, m, dfn[N], low[N], t, in_st[N], st[N], top, col[N], cnt, s[N];
ll a[N], f[N];struct edge {int v, w, r;
};vector<edge> e[N];
vector<pair<int, int>> ee[N];void tarjan(int u) {low[u] = dfn[u] = ++t;st[++top] = u;in_st[u] = 1;for (auto x: e[u]) {int v = x.v;if (!dfn[v]) {tarjan(v);low[u] = min(low[u], low[v]);} else if (in_st[v]) {low[u] = min(low[u], dfn[v]);}}if (low[u] == dfn[u]) {++cnt;int j = 0;while (st[top + 1] != u) {in_st[st[top]] = 0;col[st[top]] = cnt;s[j++] = st[top];top--;}for (int i = 0; i < j; i++) {for (auto x: e[s[i]]) {if (col[x.v] == cnt) {int y = x.w;while (y > 0) {a[cnt] += y;y = y * x.r / 10;}}}}}
}void dfs(int u) {for (auto [v, w]: ee[u]) {dfs(v);f[u] = max(f[u], f[v] + w);}f[u] += a[u];
}int main() {cin >> n >> m;for (int i = 1; i <= m; i++) {int x, y, w;float r;cin >> x >> y >> w >> r;e[x].push_back({y, w, int(r * 10)});}int S;cin >> S;tarjan(S);for (int i = 1; i <= n; i++) {if (!dfn[i]) continue;for (auto x: e[i])if (col[x.v] != col[i])ee[col[i]].emplace_back(col[x.v], x.w);}dfs(col[S]);cout << f[col[S]];return 0;
}