Tarjan算法总结
强联通分量
点击查看代码
#include<bits/stdc++.h>
using namespace std;
int n,m;
vector<int> e[10005];
int dfn[10005],low[10005],timtp;
int stk[10005],stktp;
bool instk[10005];
int scccnt,inscc[10005];
vector<int> scc[10005];
bool vis[10005];
void tarjan(int x){
dfn[x] = low[x] = ++timtp;
stk[++stktp] = x;instk[x] = 1;
for(auto y:e[x]){
if(!dfn[y]){
tarjan(y);
low[x] = min(low[x],low[y]);
}
else if(instk[y]) low[x] = min(low[x],dfn[y]);
}
if(low[x] >= dfn[x]){
scccnt++;
int y;
do{
y = stk[stktp--];
instk[y] = 0;
inscc[y] = scccnt;
scc[scccnt].push_back(y);
}while(y != x);
}
}
signed main(){
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 << scccnt << endl;
for(int i = 1;i <= n;++ i){
if(vis[inscc[i]]) continue;
vis[inscc[i]] = 1;
int w = inscc[i];
sort(scc[w].begin(),scc[w].end());
for(auto x:scc[w]) cout << x << " ";
cout << endl;
}
return 0;
}
缩点
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,m;
int a[10005];
struct bian{
int u,v;
}b[100005];
vector<int> e[10005];
vector<int> e2[10005];
int a2[10005];
int dfn[10005],low[10005],timtp;
int stk[10005],stktp;
int instk[10005];
int beinscc[10005];
int cntscc;
int sizscc[10005];
void dfs(int x){
dfn[x] = low[x] = ++timtp;
stk[++stktp] = x;instk[x] = 1;
for(auto y:e[x]){
if(!dfn[y]){
dfs(y);
low[x] = min(low[x],low[y]);
}
else if(instk[y]) low[x] = min(low[x],dfn[y]);
}
if(low[x] == dfn[x]){
cntscc++;
int y;
do{
y = stk[stktp--];
instk[y] = 0;
sizscc[cntscc] += a[y];
beinscc[y] = cntscc;
}while(y != x);
}
}
int ind[10005];
int ds[10005];
signed main(){
cin >> n >> m;
for(int i = 1;i <= n;++ i)
cin >> a[i];
for(int i = 1;i <= m;++ i){
int u,v;
cin >> u >> v;
b[i] = {u,v};
e[u].push_back(v);
}
for(int i = 1;i <= n;++ i)
if(!dfn[i]) dfs(i);
for(int i = 1;i <= m;++ i){
if(beinscc[b[i].u] != beinscc[b[i].v]){
int u = beinscc[b[i].u];
int v = beinscc[b[i].v];
e2[u].push_back(v);
ind[v]++;
}
}
for(int i = 1;i <= cntscc;++ i)
a2[i] = sizscc[i];
queue<int> q;
for(int i = 1;i <= cntscc;++ i)
if(ind[i] == 0) ds[i] = a2[i],q.push(i);
while(!q.empty()){
int x = q.front();q.pop();
for(auto y:e2[x]){
ds[y] = max(ds[y],a2[y]+ds[x]);
ind[y]--;
if(!ind[y]) q.push(y);
}
}
int ans = 0;
for(int i = 1;i <= cntscc;++ i)
ans = max(ans,ds[i]);
cout << ans;
return 0;
}
割点
点击查看代码
#include<bits/stdc++.h>
using namespace std;
int n,m;
vector<int> e[20005];
int dfn[20005],low[20005],timtp;
int gdcnt,isgd[20005];
void tarjan(int x,int com){
dfn[x] = low[x] = ++timtp;
int child = 0;
for(auto y:e[x]){
if(!dfn[y]){
tarjan(y,com);
low[x] = min(low[x],low[y]);
child++;
if(low[y] >= dfn[x]&&x != com)
gdcnt += (!isgd[x]),isgd[x] = 1;
}
else low[x] = min(low[x],dfn[y]);
}
if(x == com&&child >= 2) gdcnt += (!isgd[x]),isgd[x] = 1;
}
signed main(){
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 << gdcnt << endl;
for(int i = 1;i <= n;++ i)
if(isgd[i]) cout << i << " ";
return 0;
}
点双联通分量
点击查看代码
#include<bits/stdc++.h>
using namespace std;
int n,m;
vector<int> e[500005];
int dfn[500005],low[500005],timtp;
int stk[500005],stktp;
int scccnt;
vector<int> scc[500005];
void tarjan(int x,int root){
dfn[x] = low[x] = ++timtp;
stk[++stktp] = x;
int child = 0;
for(auto y:e[x]){
if(!dfn[y]){
tarjan(y,root);
low[x] = min(low[x],low[y]);
if(low[y] >= dfn[x]){
scccnt++;
int w;
do{
w = stk[stktp--];
scc[scccnt].push_back(w);
}while(w != y);
scc[scccnt].push_back(x);
}
child++;
}
else low[x] = min(low[x],dfn[y]);
}
if(x == root&&child == 0)
scc[++scccnt].push_back(x);
}
signed main(){
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]) stktp = 0,tarjan(i,i);
cout << scccnt << endl;
for(int i = 1;i <= scccnt;++ i){
cout << scc[i].size() << " ";
for(auto x:scc[i]) cout << x << " ";
cout << endl;
}
return 0;
}
边双联通分量
点击查看代码
#include<bits/stdc++.h>
using namespace std;
int n,m,w_wo_o;
vector<pair<int,int> > e[500005];
int dfn[500005],low[500005],timtp;
int scccnt;
vector<int> scc[500005];
int stk[500005],stktp;
void tarjan(int x,int com){
dfn[x] = low[x] = ++timtp;
stk[++stktp] = x;
for(auto [y,whe]:e[x]){
if(!dfn[y]){
tarjan(y,whe);
low[x] = min(low[x],low[y]);
}
else if(whe != (com^1)) low[x] = min(low[x],dfn[y]);
}
if(low[x] == dfn[x]){
scccnt++;
int w;
do{
w = stk[stktp--];
scc[scccnt].push_back(w);
}while(w != x);
}
}
signed main(){
cin >> n >> m;
for(int i = 1;i <= m;++ i){
int u,v;
cin >> u >> v;
e[u].push_back({v,w_wo_o++});
e[v].push_back({u,w_wo_o++});
}
for(int i = 1;i <= n;++ i)
if(!dfn[i]) stktp = 0,tarjan(i,-1);
cout << scccnt << endl;
for(int i = 1;i <= scccnt;++ i){
cout << scc[i].size() << " ";
for(auto x:scc[i]) cout << x << " ";
cout << endl;
}
return 0;
}
没有栈的是:割点,点双
本文中的缩点是割边,但平常要视情况而定。

浙公网安备 33010602011771号