zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    java后端工具积累
    Java基础面试题整理
    MySql常问面试题
    jvm及并发面试题
    中间件redis kafka面试题
    笔记
    解决Git操作报错
    view的state和drawable的state 源码分析
    flutter_6_动态化简介
    有关namespace 命名空间
  • 原文地址:https://www.cnblogs.com/smallhester/p/11606819.html
Copyright © 2011-2022 走看看