边双连通分量

边双连通分量

我们令双连通表示两个节点之间段开一条边还是连通的。

边双连通分量 表示求出几个最大的点集, 使得任意一个点集中点两两双连通。

例题 luoguP8436

方法1

我们发现, 如果两个节点原先连通但不是双连通, 肯定他们之间的路径是经过某一座桥, 所以可以求出来桥, 把桥拆掉, 再求连通块。

#include<bits/stdc++.h>

using namespace std;

const int N = 2e6 + 5;

struct Edge{
  int v, w;
};

int tot, cnt, cn[N], dfn[N], low[N], vis[N], n, m, u, v;

vector<Edge>g[N];

vector<int>e[N];

void dfs(int x, int f){
  dfn[x] = low[x] = ++cnt;
  for(auto [v, w] : g[x]){
    if(!dfn[v]){
      dfs(v, w);
      low[x] = min(low[x], low[v]);
    }
    else if(w != f){
      low[x] = min(low[x], dfn[v]);
    }
  }
  if(low[x] == dfn[x]){
    vis[f] = 1;
  }
}

void DFS(int x){
  if(cn[x]){
    return;
  }
  cn[x] = 1;
  e[tot].push_back(x);
  for(auto [v, w] : g[x]){
    if(!vis[w]){
      DFS(v);
    }
  }
}

int main(){
  cin >> n >> m;
  for(int i = 1; i <= m; ++i){
    cin >> u >> v;
    g[u].push_back({v, i});
    g[v].push_back({u, i});
  }
  for(int i = 1; i <= n; ++i){
    if(!dfn[i]){
      dfs(i, 0);
    }
  }
  for(int i = 1; i <= n; ++i){
    if(!cn[i]){
      ++tot;
      DFS(i);
    }
  }
  cout << tot << '\n';
  for(int i = 1; i <= tot; ++i){
    cout << e[i].size() << ' ';
    for(auto x : e[i]){
      cout << x << ' ';
    }
    cout << '\n';
  }
  return 0;
}

方法2

也可以在找到桥的时候用栈统计答案。

#include<bits/stdc++.h>

using namespace std;

const int N = 5e5 + 5;

struct Node{
  int a, b;
};

vector<vector<int>>ans;
vector<Node>g[N];

int n, m, dfn[N], low[N], top, stk[N], cnt, u, v;

void tarjan(int x, int fa){
  dfn[x] = low[x] = ++cnt, stk[++top] = x;
  for(auto [v, w] : g[x]){
    if(w != fa){
      if(!dfn[v]){
        tarjan(v, w);
        low[x] = min(low[x], low[v]);
      }
      else{
        low[x] = min(low[x], dfn[v]);
      }
    }
  }
  if(low[x] == dfn[x]){
    vector<int>v;
    for(; dfn[stk[top]] >= dfn[x]; v.push_back(stk[top--])){
    }
    ans.push_back(v);
  }
}

int main(){
  cin >> n >> m;
  for(int i = 1; i <= m; ++i){
    cin >> u >> v;
    g[u].push_back({v, i});
    g[v].push_back({u, i});
  }
  for(int i = 1; i <= n; ++i){
    if(!dfn[i]){
      tarjan(i, 0);
    }
  }
  cout << ans.size() <<'\n';
  for(auto a : ans){
    cout << a.size() << ' ';
    for(auto b : a){
      cout << b << ' ';
    }
    cout << '\n';
  }
  return 0;
}

posted @ 2024-04-09 16:01  liuyichen  阅读(2)  评论(0编辑  收藏  举报