zoukankan      html  css  js  c++  java
  • CF962F Simple Cycles Edges

    CF962F Simple Cycles Edges

    给定一个连通无向图,求有多少条边仅被包含在一个简单环内并输出

    (n, mleq10^5)

    tarjan


    首先,一个连通块是一个环,当且仅当该连通块的 点数=边数

    可以发现,如果两个环仅由一个公共点连接,那么这两个环互不影响,即点双两两互不影响。

    所以我们可以考虑处理出点双和每个点双内的边数

    但是求出点双后暴力dfs会被如下数据卡掉:

    66667 99999
    1 2
    1 3
    2 3
    1 4
    1 5
    4 5
    1 6
    1 7
    6 7
    ...
    

    因为 (1) 节点每次枚举所有边的效率太低

    于是可以在tarjan时将所有边压入栈中,再用set统计点双中的边数以及答案并去重

    时间复杂度 (O(n+m))

    代码

    #include <bits/stdc++.h>
    using namespace std;
    
    #define nc getchar()
    const int maxn = 1e5 + 10;
    int n, m, tot, top, h[maxn], dfn[maxn], low[maxn], st[maxn * 3];
    struct edges {
      int nxt, to;
    } e[maxn << 1];
    set <int> ans, edge[maxn], node[maxn];
    
    inline int read() {
      int x = 0; char c = nc;
      while (c < 48) c = nc;
      while (c > 47) x = x * 10 + c - 48, c = nc;
      return x;
    }
    
    void addline(int u, int v) {
      static int cnt = 1;
      e[++cnt] = edges{h[u], v}, h[u] = cnt;
    }
    
    void tarjan(int u, int f) {
      static int now;
      dfn[u] = low[u] = ++now;
      for (int i = h[u]; i; i = e[i].nxt) {
        int v = e[i].to;
        if (!dfn[v]) {
          st[++top] = i >> 1, st[++top] = u, st[++top] = v;
          tarjan(v, u);
          low[u] = min(low[u], low[v]);
          if (dfn[u] <= low[v]) {
            tot++;
            while (1) {
              int t1, t2;
              node[tot].insert(t1 = st[top--]);
              node[tot].insert(t2 = st[top--]);
              edge[tot].insert(st[top--]);
              if (t1 == v && t2 == u) break;
            }
          }
        } else if (dfn[v] < dfn[u] && v != f) {
          st[++top] = i >> 1, st[++top] = u, st[++top] = v;
          low[u] = min(low[u], dfn[v]);
        }
      }
    }
    
    int main() {
      n = read(), m = read();
      for (int i = 1; i <= m; i++) {
        int u = read(), v = read();
        addline(u, v), addline(v, u);
      }
      for (int i = 1; i <= n; i++) {
        if (!dfn[i]) tarjan(i, 0);
      }
      for (int i = 1; i <= tot; i++) {
        if (edge[i].size() == node[i].size()) {
          ans.insert(edge[i].begin(), edge[i].end());
        }
      }
      printf("%d
    ", (int)ans.size());
      for (int u : ans) printf("%d ", u);
      return 0;
    }
    
  • 相关阅读:
    磁盘映射命令
    CentOS 配置XWIN/VNC
    生成一个随机数,让用户输入猜这个数字,有三次机会
    自己练习读取写入txt
    python学习笔记:文件操作和集合(转)
    接口测试基础
    nginx_tomcat负载均衡环境
    mysql索引
    shell脚本
    linux基础知识(四)
  • 原文地址:https://www.cnblogs.com/Juanzhang/p/10374869.html
Copyright © 2011-2022 走看看