强连通分量 缩点

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int mod = 1e9 + 7;
const int N = 2e5 + 10;
int n, m;
int low[N], dfn[N], tot;
int scc[N], siz[N], cnt;
set<int> f[N];
vector<int> e[N];
stack<int> st;
int insta[N];
void tarjan(int u){
low[u] = dfn[u] = ++tot;
st.push(u);
insta[u] = 1;
for(auto v : e[u]){
if(!dfn[v]){
tarjan(v);
low[u] = min(low[u], low[v]);
}
else if(insta[v]){
low[u] = min(low[u], dfn[v]);
}
}
if(dfn[u] == low[u]){
cnt++;
while(!st.empty()){
auto t = st.top();
st.pop();
insta[t] = 0;
scc[t] = cnt;
f[cnt].insert(t);
siz[cnt]++;
if(t == u) break;
}
}
}
void solve(){
cin >> n >> m;
for(int i = 1; i <= m; i++){
int u, v;
cin >> u >> v;
e[u].push_back(v);
}
for(int i = 1; i <= n; i++){
if(!dfn[i]) tarjan(i);
}
cout << cnt <<endl;
// for(int i = 1; i <= cnt; i++){
// cout << siz[i] << ' ';
// }
// cout << endl;
for(int i = 1; i <= n; i++){
if(dfn[i]){
int id = scc[i];
for(auto j : f[id]){
cout << j << ' ';
dfn[j] = 0;
}
cout << endl;
}
}
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t = 1;
// cin >> t;
while (t--){
solve();
}
return 0;
}
割点割顶

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int mod = 1e9 + 7;
const int N = 2e5 + 10;
int n, m;
int low[N], dfn[N], tot;
vector<int> e[N];
set<int> f;
int cut[N];
int root;
void tarjan(int u, int ro){
low[u] = dfn[u] = ++tot;
int child = 0;
for(auto v : e[u]){
if(!dfn[v]){
tarjan(v, ro);
child ++;
low[u] = min(low[u], low[v]);
if(low[v] >= dfn[u]){
if(u != ro || child >= 2){
cut[u] = 1;
f.insert(u);
}
}
}
else{
low[u] = min(low[u], dfn[v]);
}
}
}
void solve(){
cin >> n >> m;
for(int i = 1; i <= m; i++){
int u, v;
cin >> u >> v;
e[u].push_back(v);
e[v].push_back(u);
}
for(int i = 1; i <= n; i++){
if(!dfn[i]){
tarjan(i, i);
}
}
cout << f.size() << endl;
for(auto i : f){
cout << i << ' ';
}
cout << endl;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t = 1;
// cin >> t;
while (t--){
solve();
}
return 0;
}
割边

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int mod = 1e9 + 7;
const int N = 2e5 + 10;
int n, m;
int low[N], dfn[N], tot;
struct edge{
int u, v;
};
struct Bridge{
int u, v;
}bri[N];
int cnt;
vector<edge> e;
vector<int> h[N];
void add(int u, int v){
e.push_back({u, v});
h[u].push_back(e.size() - 1);
}
void tarjan(int u, int idd){
low[u] = dfn[u] = ++tot;
for(int i = 0; i < h[u].size(); i++){
int id = h[u][i], v = e[id].v;
if(!dfn[v]){
tarjan(v, id);
low[u] = min(low[u], low[v]);
if(low[v] > dfn[u]){
bri[++cnt] = {u,v};
}
}
else if(id != (idd ^ 1)){
low[u] = min(low[u], dfn[v]);
}
}
}
void solve(){
cin >> n >> m;
for(int i = 1; i <= m; i++){
int u, v;
cin >> u >> v;
add(u, v);
add(v, u);
}
for(int i = 1; i <= n; i++){
if(!dfn[i]){
tarjan(i, 0);
}
}
sort(bri + 1, bri + 1 + cnt, [&](Bridge a, Bridge b){
if(a.u == b.u) return a.v < b.v;
return a.u < b.u;
});
for(int i = 1; i <= cnt; i++){
cout << bri[i].u << ' ' << bri[i].v << endl;
}
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t = 1;
// cin >> t;
while (t--){
solve();
}
return 0;
}
eDcc缩点
按照割边分开然后分成若干双连通分量 scc缩点变成的是有向有环拓扑图 eDcc变成的是无向无环树
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int mod = 998244353;
const int N = 3e5 + 10;
int n, m;
struct edge{
int u, v;
};
vector<edge> e;
vector<int> h[N];
int dfn[N], low[N], tot;
stack<int> sta;
int dcc[N], d[N], cnt, cnt1;
struct Bri{
int u, v;
}bri[N];
void add(int u, int v){
e.push_back({u, v});
h[u].push_back(e.size() - 1);
}
void tarjan(int u, int in_edg){
dfn[u] = low[u] = ++tot;
sta.push(u);
for(int i = 0; i < h[u].size(); i++){
int id = h[u][i], v = e[id].v;
if(!dfn[v]){
tarjan(v, id);
low[u] = min(low[u], low[v]);
if(low[v] > dfn[u]){
bri[++cnt1] = {u, v};
}
}
else if(id != (in_edg ^ 1)){
low[u] = min(low[u], dfn[v]);
}
}
if(low[u] == dfn[u]){
++cnt;
while(!sta.empty()){
auto t = sta.top();
sta.pop();
dcc[t] = cnt;
if(t == u) break;
}
}
}
void solve(){
cin >> n >> m;
while(m--){
int u, v;
cin >> u >> v;
add(u, v), add(v, u);
}
for(int i = 1; i <= n; i++){
if(!dfn[i]) tarjan(i, 0);
}
for(int i = 1; i <= cnt1; i++){
d[dcc[bri[i].u]]++;
d[dcc[bri[i].v]]++;
}
int sum = 0;
for(int i = 1; i <= cnt; i++){
if(d[i] == 1){
sum++;
}
}
cout << (sum + 1) / 2 << endl;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int T = 1;
// cin >> T;
while(T--){
solve();
}
}
vdcc 缩点
按割点分开
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int mod = 998244353;
const int N = 5e5 + 10;
int n, m;
vector<int> e[N], dcc[N];
int dfn[N], low[N], tot;
stack<int> sta;
int cut[N], cnt;
void tarjan(int u, int root)
{
dfn[u] = low[u] = ++tot;
sta.push(u);
if (!e[u].size())
{
dcc[++cnt].push_back(u);
sta.pop();
return;
}
int child = 0;
for (auto v : e[u])
{
if (!dfn[v])
{
tarjan(v, root);
low[u] = min(low[u], low[v]);
if (low[v] >= dfn[u])
{
child++;
if (u != root || child >= 2) cut[u] = 1;
cnt++;
while (sta.size())
{
auto t = sta.top();
sta.pop();
dcc[cnt].push_back(t);
if (t == v)
break;
}
dcc[cnt].push_back(u);
}
}
else{
low[u] = min(low[u], dfn[v]);
}
}
}
void solve()
{
cin >> n >> m;
while (m--)
{
int u, v;
cin >> u >> v;
if(u == v) continue; //忽略自环
e[u].push_back(v);
e[v].push_back(u);
}
for(int i = 1; i <= n; i++){
if(!dfn[i]){
tarjan(i, i);
}
}
cout << cnt << endl;
for(int i = 1; i <= cnt; i++){
cout << dcc[i].size() << ' ';
for(auto j : dcc[i]){
cout << j << ' ';
}
cout << endl;
}
/*
vDcc缩点
int num = cnt;
for(int i = 1; i <=n; i++){
if(cut[i]) id[i] = ++num;
}
for(int i = 1; i <= cnt; i++){
for(int j = 0; j < dcc[i].size(); i++){
int dot = dcc[i][j];
if(cut[dot]){
//存新图的 vector<int> ne[N];
ne[i].pb(id[dot]);
ne[id[dot]].pb(i);
}
}
}
*/
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int T = 1;
// cin >> T;
while (T--)
{
solve();
}
}