P2656 采蘑菇
题意:
有n个点,m个单向边,每个边都有边权,如果经过这个边,可以获得其边权,而其边权会变成原来的p倍(0.1<=p<=0.8),向下取整
从s点出发,问最多可以采到的蘑菇
题解:
因为是单向边,除非出现一个环,不然每个边最多只能走一次,如果有一个环,环上的边权可以一直获取,直到边权为0.
所以我们可以用tarjan进行缩点,将这个环上所有得到的价值加起来,赋给缩成的点x。
缩完点后,就同时有点权(在之前环上所能获取的价值)和边权,且无环,那直接跑一个拓扑+dp就可以,在拓扑过程中转移dp,然后取最大即可
总结:tarjan缩点+拓扑dp
代码:
// Problem: P2656 采蘑菇
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P2656
// Memory Limit: 125 MB
// Time Limit: 1000 ms
// By Jozky#include <bits/stdc++.h>
#include <unordered_map>
#define debug(a, b) printf("%s = %d\n", a, b);
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> PII;
clock_t startTime, endTime;
//Fe~Jozky
const ll INF_ll= 1e18;
const int INF_int= 0x3f3f3f3f;
void read(){};
template <typename _Tp, typename... _Tps> void read(_Tp& x, _Tps&... Ar)
{x= 0;char c= getchar();bool flag= 0;while (c < '0' || c > '9')flag|= (c == '-'), c= getchar();while (c >= '0' && c <= '9')x= (x << 3) + (x << 1) + (c ^ 48), c= getchar();if (flag)x= -x;read(Ar...);
}
template <typename T> inline void write(T x)
{if (x < 0) {x= ~(x - 1);putchar('-');}if (x > 9)write(x / 10);putchar(x % 10 + '0');
}
void rd_test()
{
#ifdef ONLINE_JUDGE
#elsestartTime= clock();freopen("data.in", "r", stdin);
#endif
}
void Time_test()
{
#ifdef ONLINE_JUDGE
#elseendTime= clock();printf("\nRun Time:%lfs\n", (double)(endTime - startTime) / CLOCKS_PER_SEC);
#endif
}
const int maxn= 3e5 + 9;
double hui[maxn];
int n, m;
struct node{int v,w;double k;
};
vector<node>vec[maxn];
int dfn[maxn], low[maxn], vis[maxn];
int color[maxn];
int tot= 0, col= 0;
int degree[maxn];
vector<PII> vec2[maxn];
vector<int> co[maxn];
int newa[maxn];
stack<int> s;
void tarjan(int x)
{vis[x]= 1;dfn[x]= low[x]= ++tot;s.push(x);for (auto it : vec[x]) {int v= it.v;int w= it.w;if (!dfn[v]) {tarjan(v);low[x]= min(low[x], low[v]);}else if (vis[v]) {low[x]= min(low[x], dfn[v]);}}if (dfn[x] == low[x]) {col++;while (1) {int top= s.top();s.pop();color[top]= col;vis[top]= 0;if (top == x)break;}}
}
int dp[maxn];
void solve()
{for (int i= 1; i <= n; i++) {if (!dfn[i])tarjan(i);}for (int i= 1; i <= n; i++) {for (auto it : vec[i]) {int v= it.v;int w= it.w;double k=it.k;if (color[i] != color[v]) {degree[color[v]]++;vec2[color[i]].push_back({color[v], w});}else {while(w){newa[color[v]]+=w;w=w*k/10;}}}}
}
void troop(int s)
{queue<int> q;for(int i=1;i<=col;i++){if(!degree[i])q.push(i);dp[i]=-INF_int;}dp[color[s]]=newa[color[s]];q.push(s);while (!q.empty()) {int u= q.front();q.pop();for (auto it : vec2[u]) {int v= it.first;int w= it.second;degree[v]--;dp[v]= max(dp[v], dp[u] + newa[v] + w);if (!degree[v])q.push(v);}}
}
int main()
{rd_test();read(n, m);for (int i= 1; i <= m; i++) {int u, v, w;double s;scanf("%d%d%d%lf", &u, &v, &w, &s);vec[u].push_back({v, w,s*10});}int s;read(s);solve();troop(s);int maxx= 0;for (int i= 1; i <= col; i++)maxx= max(dp[i], maxx);cout << maxx;//Time_test();
}
//92