首页 > 其他分享 >Luogu P2656采蘑菇(Tarjan + spfa)

Luogu P2656采蘑菇(Tarjan + spfa)

时间:2022-10-21 15:33:31浏览次数:78  
标签:std Tarjan int Luogu cnt vector low 蘑菇 P2656

采蘑菇

题目描述

小胖和 ZYR 要去 ESQMS 森林采蘑菇。

ESQMS 森林间有 \(N\) 个小树丛,\(M\) 条小径,每条小径都是单向的,连接两个小树丛,上面都有一定数量的蘑菇。小胖和 ZYR 经过某条小径一次,可以采走这条路上所有的蘑菇。由于 ESQMS 森林是一片神奇的沃土,所以一条路上的蘑菇被采过后,又会长出一些新的蘑菇,数量为原来蘑菇的数量乘上这条路的“恢复系数”,再下取整。

比如,一条路上有 \(4\) 个蘑菇,这条路的“恢复系数”为 \(0.7\),则第一~四次经过这条路径所能采到的蘑菇数量分别为 \(4,2,1,0\)。

现在,小胖和 ZYR 从 \(S\) 号小树丛出发,求他们最多能采到多少蘑菇。

思路

由于每一条边都是可以重复经过得,所以考虑找到一个环使得将环内所有得蘑菇都采集完后,再进入下一个环,这样得采集方式可以使得最后得答案最大。那么这些环上得点可以缩成一个点,让这个环上所有得贡献都变成缩点后得点权。将所有得联通分量缩点之后,就是一个有向无环得图,这样就可以考虑从起点 \(S\) 出发求得到达每一个点得最大贡献是多少从而确定最后得答案,也就是在 \(DAG\) 上用 \(spfa\) 跑一遍最长路。

    std::cin.tie(nullptr)->sync_with_stdio(false);

    int n, m;
    std::cin >> n >> m;
    std::vector<std::array<int, 3>> G[n + 1];
    for (int i = 1; i <= m; i++) {
        int u, v, w;
        double k;
        std::cin >> u >> v >> w >> k;
        G[u].push_back({v, w, k * 10});
    }

    std::vector<int> dfn(n + 1), stk(n + 1), low(n + 1);
    std::vector<int> scc(n + 1);
    std::vector<bool> vis(n + 1);
    int idx = 0, top = 0, cnt = 0;
    // idx是时间戳,top是栈的指针,cnt是强连通分量的数量->缩点的个数

    std::function<void(int)> tarjan = [&] (int u) -> void {
        dfn[u] = low[u] = ++ idx;
        stk[++top] = u;
        vis[u] = true;

        for (auto& [v, w, k] : G[u]) {
            if (!dfn[v]) {
                tarjan(v);
                low[u] = std::min(low[u], low[v]);
            } else if (vis[v]) {
                low[u] = std::min(low[u], dfn[v]);
            }
        }

        if (dfn[u] == low[u]) {//时间戳和回溯点是同一个那就是缩点
            int v = 0;
            cnt++;
            do {
                v = stk[top--];
                vis[v] = false;
                scc[v] = cnt;
            } while(v != u);
        }
    };

    for (int i = 1; i <= n; i++) {
        if (!dfn[i]) tarjan(i);
    }

    std::vector<std::array<int, 2>> adj[cnt + 1];
    std::vector<int> sum(cnt + 1);
    for (int i = 1; i <= n; i++) {
        for (auto& [v, w, k] : G[i]) {
            if (scc[i] == scc[v]) {
                while(w) sum[scc[i]] += w, w = w * k / 10;
            } else {
                adj[scc[i]].push_back({scc[v], w});
            }
        }
    }

    int s; std::cin >> s;
    s = scc[s];

    std::queue<int> q;
    q.push(s);
    std::vector<int> dist(cnt + 1, -1);
    std::vector<bool> st(cnt + 1);
    st[s] = true;
    dist[s] = sum[s];
    while(!q.empty()) {
        int u = q.front();
        q.pop();
        st[u] = false;

        for (auto& [v, w] : adj[u]) {
            if (dist[v] < dist[u] + w + sum[v]) {
                dist[v] = dist[u] + w + sum[v];
                if (!st[v]) {
                    st[v] = true;
                    q.push(v);
                }
            }
        }
    }

    std::cout << *max_element(all(dist)) << "\n";

    return 0 ^ 0;

标签:std,Tarjan,int,Luogu,cnt,vector,low,蘑菇,P2656
From: https://www.cnblogs.com/Haven-/p/16813649.html

相关文章

  • 【luogu AGC034F】RNG and XOR(FWT)
    RNGandXOR题目链接:luoguAGC034F题目大意给你一个长度为2^n的数组A。一开始有一个\(0\)数,然后每次你随机给它异或上0~2^n-1中的数,随机到\(i\)的概率跟Ai+1......
  • luogu P1972 SDOI2009 HH的项链
    P1972SDOI2009HH的项链-洛谷|计算机科学教育新生态(luogu.com.cn)维护一个长度同为\(n\)的数组\(b\)。一个指针\(R\)从\(1\)扫到\(n\)并做如下操作:检查......
  • Tarjan算法
    Tarjan算法1算法简介还记得无向图判连通块吗?对于无向图中,判连通块是一件很容易的事。你只需要dfs(深度优先搜索)一下就可以了。但是,如果我们把无向图换成有向图呢?这......
  • 【luogu CF1163F】Indecisive Taxi Fee(图论)(分类讨论)
    IndecisiveTaxiFee题目链接:luoguCF1163F题目大意给你一个无向图,每次改一条边的权值(每次都会变回来),问你1~n的最短路长度。思路考虑分类讨论,先找到最短路的路径,然......
  • 【luogu CF1140F】Extending Set of Points(线段树分治)
    ExtendingSetofPoints题目链接:luoguCF1140F题目大意有一个点集,有一个扩展操作是加入符合条件的(x0,y0)直到不能加入位置。符合条件是原来(x0,y0)不存在而且存......
  • 做题记录整理图论/tarjan P5058 [ZJOI2004]嗅探器(2022/10/19)
    P5058[ZJOI2004]嗅探器首先,我们应该马上发现它求的和割点非常像,但是是对于两个点而言的割点这时候就需要对tarjan有着比较深入的理解(也可能是我太拉了)如果我们以其中一......
  • 【图论复习】Tarjan 算法(Tarjan LCA 除外)
    好久没写Tarjan,反正也快CSP了,赶紧复习一下。Tarjan就是基于dfs树中的dfs序以及low数组来进行搜索,注意不同的算法low的更新时不一样的,其他的感觉没什么好讲的......
  • luogu P3685 [CERC2016]不可见的整数 Invisible Integers
    题面传送门真的吐了,写了五六个小时。首先我们不考虑两边都能走,只考虑向左走,那么的话如果两个从左到右的集合分别为\(S1,S2\),则\(S1\subsetS2\),且除去\(S1\)已经匹配掉的......
  • Tarjan总结
    Tarjan算法基于深度优先遍历,可在\(O(n)\)的时间复杂度下处理问题一.Tarjan算法在无向图上的应用:1.Tarjan求桥structTarjan_Bridge//无向图桥{structEdge......
  • luogu P5339 [TJOI2019]唱、跳、rap和篮球 (容斥,指数型母函数,NTT)
    https://www.luogu.com.cn/problem/P5339要求不含1234的方案,反过来求含至少一个1234的方案。钦定存在i个位置有1234,位置的方案是Cn-3i,i.其他n-4i个位置的方案是多重集......