P2656 采蘑菇

Posted Jozky86

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P2656 采蘑菇相关的知识,希望对你有一定的参考价值。

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 采蘑菇的主要内容,如果未能解决你的问题,请参考以下文章

P2656 采蘑菇 - Tarjan缩点+SPFA

P2656 采蘑菇

Luogu P2656 采蘑菇

树形DP

树形DP

采蘑菇