做完缩点兴冲冲地跑过来做采蘑菇,然后发现不会缩边,看题解才知道依旧是缩点,求点权加边权的最大值就行了;)
一、预处理出每条边可以采的最多蘑菇数量
二、跑一遍tarjan,用to数组保存此点对应新图的那个点
三、缩点,将强连通每条边的最多采集数加在val数组上
#include <bits/stdc++.h>
using namespace std;
#define rep(i, l, r) for (int i = (int)l; i <= (int)r; i++)
#define maxn 80004
bool vis[maxn];
int val[maxn], dfn[maxn], low[maxn], to[maxn], dp[maxn], cnt, cot, ans;
struct eage
{
int to, val, tot;
};
vector<eage> e[maxn], now[maxn];
vector<int> st;
void tarjan(int u)
{
low[u] = dfn[u] = ++cnt;
st.push_back(u);
vis[u] = 1;
for (auto v : e[u])
{
if (!dfn[v.to])
{
tarjan(v.to);
low[u] = min(low[u], low[v.to]);
}
else if (vis[v.to])
low[u] = min(low[u], low[v.to]);//如果是求割点应该将low[v.to]换成dfn[v.to]
}
if (dfn[u] == low[u])//如果是强连通块就存起来
{
cot++;
int t = -1;
while (t != u)
{
t = st.back();
vis[t] = 0;
st.pop_back();
to[t] = cot;
}
}
}
int dfs(int u)//记忆化搜索
{
if (dp[u])
return dp[u];
for (auto v : now[u])
dp[u] = max(dp[u], v.val + dfs(v.to));
return dp[u] = dp[u] + val[u];//加上点权
}
int main()
{
int n, m, s; cin >> n >> m;
rep(i, 1, m)
{
int u, v, val;double r;
cin >> u >> v >> val >> r;
int sum = val, add = val * r;
while (add)
{
sum += add;
add = add * r;//预处理能采摘的最大蘑菇数
}
e[u].push_back({v, val, sum});
}
cin >> s;
rep(i, 1, n) if (!dfn[i]) tarjan(i);
rep(i, 1, n)
{
for (auto j : e[i])
if (to[i] != to[j.to]) now[to[i]].push_back({to[j.to], j.val, j.tot});
else val[to[i]] += j.tot;
}
cout << dfs(to[s]);
return 0;
}