P2656 采蘑菇
Posted Jozky86
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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
#else
startTime= clock();
freopen("data.in", "r", stdin);
#endif
}
void Time_test()
{
#ifdef ONLINE_JUDGE
#else
endTime= 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=floor(w*k);
}
}
}
}
}
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});
}
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
以上是关于P2656 采蘑菇的主要内容,如果未能解决你的问题,请参考以下文章