zoukankan      html  css  js  c++  java
  • Luogu2860 [USACO06JAN]冗余路径Redundant Paths

    Luogu2860 [USACO06JAN]冗余路径Redundant Paths

    给定一个连通无向图,求至少加多少条边才能使得原图变为边双连通分量

    (1leq nleq5000, n-1leq mleq10^4)

    tarjan


    边双无疑不用考虑,于是就可以边双缩点成一棵树

    令现在要连的边为 ((u, v)) ,当前树上 (bl_u)(bl_v) 的链将会变为一个新的点双,可以将他们看为一个新的点

    可以贪心地连边使得每次连边后,不复存在的点尽量多,当只剩一个点时,原图就变成了一个双连通分量

    如果 (u) 为非叶节点,显然不如将 (u) 子树中的一点 (u')(v) 连接,于是 (u, v) 均为叶节点

    (lca(u, v))(root) ,将会消去两个叶节点,否则只会消去一个叶节点,因此每次选择 (lca(u, v))(root) 的两个点,答案即为 (叶节点的个数lfloorfrac{verb|叶节点的个数|+1}{2} floor)

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

    代码

    #include <bits/stdc++.h>
    using namespace std;
    
    #define nc getchar()
    const int maxn = 5010;
    int n, m, tot, h[maxn], bl[maxn], dfn[maxn], low[maxn], deg[maxn]; bool vis[maxn], cut[maxn << 1];
    struct edges {
      int nxt, to;
      edges(int x = 0, int y = 0) : nxt(x), to(y) {}
    } e[maxn << 1];
    
    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]) {
          tarjan(v, u);
          low[u] = min(low[u], low[v]);
          if (dfn[u] < low[v]) cut[i] = cut[i ^ 1] = 1;
        } else if (v != f) {
          low[u] = min(low[u], dfn[v]);
        }
      }
    }
    
    void dfs(int u) {
      vis[u] = 1, bl[u] = tot;
      for (int i = h[u]; i; i = e[i].nxt) {
        int v = e[i].to;
        if (!cut[i] && !vis[v]) dfs(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);
      }
      tarjan(1, 0);
      for (int i = 1; i <= n; i++) {
        if (!vis[i]) tot++, dfs(i);
      }
      for (int u = 1; u <= n; u++) {
        for (int i = h[u]; i; i = e[i].nxt) {
          int v = e[i].to;
          if (bl[u] != bl[v]) deg[bl[v]]++;
        }
      }
      int ans = 0;
      for (int i = 1; i <= tot; i++) {
        ans += deg[i] == 1;
      }
      printf("%d", (ans + 1) >> 1);
      return 0;
    }
    
  • 相关阅读:
    网络编程之即时通信程序(聊天室)(一)通信流程简介及通信协议定制
    C#常用加密方法解析
    ASP.NET常用数据绑定控件优劣总结
    使用XPO开发时可以参考使用的架构
    渠道会上的体会
    如何利用第三方SDK开发MSN机器人以及实现语音视频?
    对 XPO 的一些问题的解答
    c++ 参数传递 之引用形参 GIS
    指针与引用的区别 GIS
    c++ const 修饰数组 GIS
  • 原文地址:https://www.cnblogs.com/Juanzhang/p/10375244.html
Copyright © 2011-2022 走看看