题目描述
小胖和 ZYR 要去 ESQMS 森林采蘑菇。
ESQMS 森林间有 N N N 个小树丛, M M M 条小径,每条小径都是单向的,连接两个小树丛,上面都有一定数量的蘑菇。小胖和 ZYR 经过某条小径一次,可以采走这条路上所有的蘑菇。由于 ESQMS 森林是一片神奇的沃土,所以一条路上的蘑菇被采过后,又会长出一些新的蘑菇,数量为原来蘑菇的数量乘上这条路的“恢复系数”,再下取整。
比如,一条路上有 4 4 4 个蘑菇,这条路的“恢复系数”为 0.7 0.7 0.7,则第一~四次经过这条路径所能采到的蘑菇数量分别为 4 , 2 , 1 , 0 4,2,1,0 4,2,1,0。
现在,小胖和 ZYR 从 S S S 号小树丛出发,求他们最多能采到多少蘑菇。
输入格式
第一行两个整数, N N N 和 M M M。
第二行到第 M + 1 M+1 M+1 行,每行四个数,分别表示一条小路的起点,终点,初始蘑菇数,恢复系数。
第 M + 2 M+2 M+2 行,一个整数 S S S。
输出格式
一行一个整数,表示最多能采到多少蘑菇,保证答案不超过 ( 2 31 − 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 ≤ 7 N\le 7 N≤7, M ≤ 15 M\le15 M≤15
另有 30 % 30\% 30% 的数据,满足所有“恢复系数”为 0 0 0。
对于 100 % 100\% 100% 的数据, 1 ≤ N ≤ 8 × 1 0 4 1 \le N\le 8\times 10^4 1≤N≤8×104, 1 ≤ M ≤ 2 × 1 0 5 1\le M\le 2\times 10^5 1≤M≤2×105, 0 ≤ 恢复系数 ≤ 0.8 0\le\text{恢复系数}\le 0.8 0≤恢复系数≤0.8 且最多有一位小数, 1 ≤ S ≤ N 1\le S\le N 1≤S≤N。
缩点、拓扑序dp - AC
一条边连接的两个点,
在同一个强连通分量内,这条边不限次数地走;
在不同强连通分量内,这条边只能走一次。
不再赘述。
使用long double。
struct Edge {
int u, v, w; db k;
} e[MAXM];
struct _Edge {
int v, w;
_Edge(int _v, int _w): v(_v), w(_w){}
};
int n, m, s, dfn[MAXN], low[MAXN], sd[MAXN], js, tot, in[MAXN], dp[MAXN], a[MAXN];
bool vis[MAXN];
vector<int> g[MAXN];
vector<_Edge> ng[MAXN];
stack<int> stk;
void tarjan(int u) {
dfn[u] = low[u] = ++tot;
stk.push(u); vis[u] = true;
for (int v : g[u]) {
if (!dfn[v]) {
tarjan(v);
ckmin(low[u], low[v]);
}
else if (vis[v]) {
ckmin(low[u], low[v]);
}
}
if (dfn[u] == low[u]) {
int t; ++js;
while (t = stk.top()) {
stk.pop();
sd[t] = js;
vis[t] = false;
if (u == t) return;
}
}
}
void toposort() {
queue<int> q;
for (int i = 1; i <= js; ++i) {
if (!in[i]) q.push(i);
}
while (!q.empty()) {
int u = q.front(); q.pop();
stk.push(u);
for (int i = 0; i < ng[u].size(); ++i) {
int v = ng[u][i].v;
if (!--in[v]) q.push(v);
}
}
}
int main() {
setIO("");
cin >> n >> m;
for (int i = 1; i <= m; ++i) {
cin >> e[i].u >> e[i].v >> e[i].w >> e[i].k;
g[e[i].u].push_back(e[i].v);
}
cin >> s;
for (int i = 1; i <= n; ++i) {
if (!dfn[i]) tarjan(i);
}
for (int i = 1; i <= m; ++i) {
if (sd[e[i].u] != sd[e[i].v]) {
ng[sd[e[i].u]].push_back(_Edge(sd[e[i].v], e[i].w));
++in[sd[e[i].v]];
}
else {
do {
a[sd[e[i].u]] += e[i].w;
e[i].w *= e[i].k;
} while (e[i].w);
}
}
toposort();
while (!stk.empty()) {
int u = stk.top(); stk.pop();
for (int i = 0; i < ng[u].size(); ++i) {
int v = ng[u][i].v, w = ng[u][i].w;
ckmax(dp[u], dp[v] + w);
}
dp[u] += a[u];
}
cout<< dp[sd[s]] << "\n";
return 0;
}