Tarjan

· · 算法·理论

Tarjan(链表)

找了半天终于找到一篇用链表的blog(

Tarjan详细讲解

Tarjan缩点后建新图模板

```cpp #include <iostream> #include <vector> #include <cstring> #include <stack> #include <cstdio> #define MAXN 10001 using namespace std; int n, m, dfn[MAXN], low[MAXN], cnt, coli, col[MAXN], nums[MAXN]; vector <int> g[MAXN], ng[MAXN]; bool vis[MAXN]; stack <int> st; void Tarjan(int u) { //cout << u << endl; dfn[u] = low[u] = ++cnt; st.push(u); vis[u] = true; for(int x = 0; x < g[u].size(); x++) { int v = g[u][x]; if(!dfn[v]) { Tarjan(v); low[u] = min(low[u], low[v]); } else if(vis[v]) low[u] = min(low[u], dfn[v]); } if(dfn[u] == low[u]) { coli++; int v; do { v = st.top(); st.pop(); vis[v] = false; col[v] = coli; nums[coli]++; } while(v != u); } } int main() { cin >> n >> m; for(int x = 0; x < m; x++) { int u, v; cin >> u >> v; g[u].push_back(v); } for(int x = 1; x <= n; x++) if(!dfn[x]) Tarjan(x); for(int x = 1; x <= n; x++) { for(int y = 0; y < g[x].size(); y++) { int v = g[x][y]; if(col[x] != col[v]) ng[col[x]].push_back(col[v]); } } for(int x = 1; x <= coli; x++) { cout << nums[x] << endl; for(int y = 0; y < ng[x].size(); y++) cout << x << " " << ng[x][y] << " "; cout << endl; } return 0; } ``` ### 这边丢一个P1551亲戚的Tarjan做法 虽然是并查集板子题但用来练Tarjan也是可以的( ```cpp #include <iostream> #include <vector> #define MAXN 100001 using namespace std; vector <int> g[MAXN]; bool vis[MAXN]; int sta[MAXN], low[MAXN], dfn[MAXN], color[MAXN], coli, sti, cnt; void Tarjan(int u) { dfn[u] = low[u] = ++cnt; sta[++sti] = u; vis[u] = true; for(int x = 0; x < g[u].size(); x++) { int v = g[u][x]; if(!dfn[v]) { Tarjan(v); low[u] = min(low[u], low[v]); } else if(vis[v]) low[u] = min(low[u], dfn[v]); } if(dfn[u] == low[u]) { coli++; while(sta[sti+1] != u) { int v = sta[sti--]; color[v] = coli; } } } int main() { int n, m, p; cin >> n >> m; for(int x = 0; x < m; x++) { int u, v; cin >> u >> v; g[u].push_back(v); g[v].push_back(u); } for(int x = 0; x < n; x++) if(!dfn[x]) Tarjan(x); cin >> p; for(int x = 0; x < p; x++) { int u, v; cin >> u >> v; if(color[u] == color[v]) cout << "Yes" << endl; else cout << "No" << endl; } return 0; } ``` ### P2835 刻录光盘(经典例题) Tarjan缩点,找入度为0的强连通分量(即必须获得资料) ```cpp #include <iostream> #include <vector> #include <cstring> #include <stack> #include <cstdio> #define MAXN 1001 using namespace std; int n, dfn[MAXN], low[MAXN], cnt, coli, col[MAXN], in[MAXN]; vector <int> g[MAXN]; bool vis[MAXN]; stack <int> st; void Tarjan(int u) { //cout << u << endl; dfn[u] = low[u] = ++cnt; st.push(u); vis[u] = true; for(int x = 0; x < g[u].size(); x++) { int v = g[u][x]; if(!dfn[v]) { Tarjan(v); low[u] = min(low[u], low[v]); } else if(vis[v]) low[u] = min(low[u], dfn[v]); } if(dfn[u] == low[u]) { coli++; int v; do { v = st.top(); st.pop(); vis[v] = false; col[v] = coli; } while(v != u); } } int main() { cin >> n; for(int x = 1; x <= n; x++) { int v; cin >> v; while(v != 0) { g[x].push_back(v); cin >> v; } } for(int x = 1; x <= n; x++) if(!dfn[x]) Tarjan(x); int ans = 0; for(int x = 1; x <= n; x++) for(int y = 0; y < g[x].size(); y++) { int v = g[x][y]; if(col[x] != col[v]) in[col[v]]++; } //for(int x = 1; x <= n; x++) cout << in[x] << " "; //cout << endl; for(int x = 1; x <= coli; x++) if(!in[x]) ans++; cout << ans << endl; return 0; } ``` ### P8436 边双连通分量模板 **其实就是无向图Tarjan模板** 这里因为数据有重边就给边加了个id记录,反向边id相同就不跑,但重边id不同就继续跑 ```cpp #include <iostream> #include <cstring> #include <vector> #include <stack> #define MAXN 500001 using namespace std; struct edge { int v, id; }; int dfn[MAXN], low[MAXN], cnt, coli; bool vis[MAXN]; stack <int> st; vector <edge> g[MAXN]; vector <int> col[MAXN]; void Tarjan(int u, int lst) { dfn[u] = low[u] = ++cnt; vis[u] = true; st.push(u); for(int x = 0; x < g[u].size(); x++) { int v = g[u][x].v, id = g[u][x].id; if(id == lst) continue; if(!dfn[v]) { Tarjan(v, id); low[u] = min(low[u], low[v]); } else if(vis[v]) low[u] = min(low[u], dfn[v]); } if(dfn[u] == low[u]) { coli++; int v; do { v = st.top(); st.pop(); vis[v] = false; col[coli].push_back(v); } while(v != u); } } int main() { int n, m; cin >> n >> m; for(int x = 1; x <= m; x++) { int u, v; cin >> u >> v; g[u].push_back((edge){v, x}); g[v].push_back((edge){u, x}); } for(int x = 1; x <= n; x++) if(!dfn[x]) Tarjan(x, 0); cout << coli << endl; for(int x = 1; x <= coli; x++) { cout << col[x].size() << " "; for(int y = 0; y < col[x].size(); y++) cout << col[x][y] << " "; cout << endl; } return 0; } ```