tarjan 缩点 + 几道例题
tarjan 模板
#include <iostream>
#include <string.h>
using namespace std;
const int MAX_N = 100;
const int MAX_M = 10000;
struct edge{
int v,next;
int len;
}E[MAX_M];
int p[MAX_N],eid;
int dfn[MAX_N],low[MAX_N];
int idx = 0;
int belong[MAX_N],scc = 0;
int s[MAX_N],top = 0;
bool in_stack[MAX_N];
void init(){
memset(p,-1,sizeof(p));
eid = 0;
}
void insert(int u,int v){
E[eid].v = v;
E[eid].next = p[u];
p[u] = eid++;
}
void tarjan(int u){
dfn[u] = low[u] = ++idx;
s[top++] = u;
in_stack[u] = true;
for(int i=p[u];i+1;i=E[i].next){
int v = E[i].v;
if(!dfn[v]){
tarjan(v);
low[u] = min(low[u],low[v]);
}else if(in_stack[v]){
low[u] = min(low[u],dfn[v]);
}
}
if(dfn[u] == low[u]){
++scc;
do{
belong[s[--top]] = scc;
in_stack[s[top]] = false;
}while(s[top] != u);
}
}
int main() {
int n,m;
init();
cin>>n>>m;
for(int i=0;i<m;i++){
int u,v;
cin>>u>>v;
insert(u,v);
}
memset(dfn,0,sizeof(dfn));
idx = 0;
for(int i=1;i<=n;i++){
if(!dfn[i]){
tarjan(i);
}
}
for(int i=1;i<=scc;i++){
cout<<"block "<<i<<": ";
for(int j=1;j<=n;j++){
if(belong[j] == i){
cout<<j<<" ";
}
}
cout<<endl;
}
return 0;
}
例题1:受欢迎的蒜头
题解地址:https://blog.csdn.net/qq_29980371/article/details/77963431
例题2:发现环(蓝桥杯第八届国赛)
题解地址:https://blog.csdn.net/cillyb/article/details/72802229
例题3:河南省第十二届ACM省赛
G题:tarjan缩点,求出强连通分量数量,统计入度为0的点,但是这样做的人都wa了。。暂且先放在这篇博文里,等时机成熟再补题。
例题4:noip2015信息传递
tarjan找最小环
https://www.luogu.org/problemnew/solution/P2661?page=2
更多:https://www.cnblogs.com/stxy-ferryman/p/7779347.html
求割点和桥:https://www.cnblogs.com/geloutingyu/p/6758624.html
求割点和桥:https://www.jianshu.com/p/d765427e07df
加上两句话:
if(dfn[u] <= low[v]) f = true;
if((!fa && son>1) || (fa && f)) cutp.push_back(u);
vector <int> cutp;//存放割点
void dfs(int u, int fa){
dfn[u] = low[u] = ++timer;
int son = 0;
bool f = false;
for(int i=0;i<E[u].size();i++){
int v = E[u][i];
if(v == fa) continue;
if(!dfn[v]){
son++;
dfs(v, u);
if(dfn[u] <= low[v]) f = true;
low[u] = min(low[u], low[v]);
}
else low[u] = min(low[u], dfn[v]);
}
if((!fa && son>1) || (fa && f)) cutp.push_back(u);
}