• 2019 CCPC 秦皇岛F Forest Program(dfs)


    传送门

    题意:给定一张无向简单图,同时规定一条边只属于一个环。可以删除任意条边使得这张图变成森林,也就是使得每一个连通块都是树。求一共有多少种方案。

    分析:由于原题规定一条边只属于一个环,不需要考虑环套环。每一种方案删除之后不能存在环,所以对于图中所有环,设环的边数为s,删除边的数量从1,2,3……s都是合法的,所以对于一个环的方案数为2^s-1。对于许多环,方案数相乘取模。同时,非环边可以任意删,所以求出所有环之后,设非环边数量为t,删除环边总方案为ans,删除非环边方案为2^t,则最后答案应当是2^t*ans。以上所有运算取模。

    找环可以使用dfs一遍求出。方法为:vis数组设置为三种状态,0表示未被访问过。1表示正在被访问,即边指向的结点是当前结点在dfs树上的祖先节点。2表示访问完毕。同时dfs的同时记录每一个结点的先驱path。如果边访问到了vis为1的数组,说明存在环,则通过path数组,从当前结点回跳到指向的结点,经过的步数为环的长度-1。

    代码:

    #include <bits/stdc++.h>
    #define mp make_pair
    #define debug(x) cout << #x << ": " << x << endl
    #define pb push_back
    typedef long long LL;
    const int maxn = 3e5 + 10;
    const int inf = 0x3f3f3f3f;
    const LL INF = 0x3f3f3f3f3f3f3f3f;
    using namespace std;
    int u, v, n, m, path[maxn], vis[maxn];
    LL ans = 1, cnt, mod = 998244353, sum = 0;
    vector<int> g[maxn];
    LL qpow(LL x) {
        LL res = 1, temp = 2;
        while (x) {
            if (x & 1) {
                res = (res * temp) % mod;
            }
            temp = (temp * temp) % mod;
            x >>= 1;
        }
        return res % mod;
    }
    void dfs(int now, int pre) {
        vis[now] = 1;
        for (int i = 0; i < g[now].size(); ++i) {
            int to = g[now][i];
            if (to == pre)
                continue;
            if (vis[to] == 0) {
                path[to] = now;
                dfs(to, now);
            }
            else if (vis[to] == 2) {
                continue;
            }
            else {
                int temp = now;
                cnt = 1;
                while (temp != to) {
                    ++cnt;
                    temp = path[temp];
                }
                sum += cnt;
                ans = (ans * (qpow(cnt) - 1)) % mod;
            }
        }
        vis[now] = 2;
    }
    int main() {
        scanf("%d %d", &n, &m);
        for (int i = 1; i <= m; ++i) {
            scanf("%d %d", &u, &v);
            g[u].push_back(v);
            g[v].push_back(u);
        }
        for (int i = 1; i <= n; ++i) {
            if (vis[i] == 0) {
                dfs(i, 0);
            }
        }
        printf("%lld
    ", qpow(m - sum) * ans % mod);
    
    }
    View Code
  • 相关阅读:
    保护环境的英语作文(精选32篇)
    SpringBoot开发 如何定制自己的Banner?还能用图片?
    一文深入浅出学习Spring框架系列,强烈推荐
    643. 子数组最大平均数 I
    528. 按权重随机选择
    497. 非重叠矩形中的随机点 ( presum+二分)
    380. O(1) 时间插入、删除和获取随机元素
    519. 随机翻转矩阵 (hash 映射移动到最后)
    480. 滑动窗口中位数
    710. 黑名单中的随机数
  • 原文地址:https://www.cnblogs.com/smallhester/p/11606819.html
Copyright © 2020-2023  润新知