tarjan

强连通分量 缩点

aa800cbea436f94ca342dd1d173d7442

#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;
}

割点割顶

48f56ed03ed30b546ae785fc22bb4521

#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;
}

割边

8601e0ad31073aa2170f25e248fb335c

#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();
    }
}

posted @ 2026-07-16 23:19  Ultramans  阅读(20)  评论(0)    收藏  举报