无向图的tarjan
求边双连通分量的个数以及每个边双连通分量的大小以及每个边双连通分量包含哪些点。bridge数组表示一条边是不是桥。
#include<bits/stdc++.h>
using namespace std;
const int N=5e5+10,M=2e6+10;
struct edge{
int x,y,pre;
}a[M*2];
int alen,last[N];
void ins(int x,int y)
{
a[++alen]={x,y,last[x]};
last[x]=alen;
}
int dfn[N],low[N],id;
bool bridge[M*2];
void tarjan(int x,int in_edge)
{
low[x]=dfn[x]=++id;
for(int k=last[x];k;k=a[k].pre)
{
int y=a[k].y;
if(!dfn[y])
{
tarjan(y,k);
low[x]=min(low[x],low[y]);
if(low[y]>dfn[x]) bridge[k]=bridge[k^1]=1;
}
else if(k!=(in_edge^1)) low[x]=min(low[x],dfn[y]);
}
}
int cnt;
bool v[N];
vector<int> dcc[N];
void dfs(int x)
{
v[x]=1;
dcc[cnt].push_back(x);
for(int k=last[x];k;k=a[k].pre)
{
int y=a[k].y;
if(v[y]||bridge[k]) continue;
dfs(y);
}
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
alen=1;memset(last,0,sizeof(last));
for(int i=1;i<=m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
if(x==y) continue;
ins(x,y),ins(y,x);
}
id=0;
for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i,-1);
for(int i=1;i<=n;i++) if(!v[i]) cnt++,dfs(i);
printf("%d\n",cnt);//边双连通分量的数目
for(int i=1;i<=cnt;i++)
{
printf("%d ",(int)dcc[i].size());//当前边双连通分量的大小
for(auto x:dcc[i]) printf("%d ",x);//当前边双连通分量包含哪些点
}
return 0;
}
点双tarjan一定要判断自环!
求一个点是不是割点。cut数组表示一个点是不是割点。
#include<bits/stdc++.h>
using namespace std;
const int N=2e4+10,M=1e5+10;
struct edge{
int x,y,pre;
}a[M*2];
int alen,last[N];
void ins(int x,int y)
{
a[++alen]={x,y,last[x]};
last[x]=alen;
}
int dfn[N],low[N],id,root;
bool cut[N];
void tarjan(int x)
{
low[x]=dfn[x]=++id;
int flag=0;
for(int k=last[x];k;k=a[k].pre)
{
int y=a[k].y;
if(!dfn[y])
{
tarjan(y);
low[x]=min(low[x],low[y]);
if(low[y]>=dfn[x])
{
flag++;
if(x!=root||flag>1) cut[x]=true;
}
}
else low[x]=min(low[x],dfn[y]);
}
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
ins(x,y),ins(y,x);
}
for(int i=1;i<=n;i++) if(!dfn[i]) root=i,tarjan(i);
int cnt=0;
for(int i=1;i<=n;i++) if(cut[i]) cnt++;
printf("%d\n",cnt);//割点的数量
for(int i=1;i<=n;i++) if(cut[i]) printf("%d ",i);//每个割点的编号
return 0;
}
求点双连通分量的个数以及每个点双连通分量的大小以及每个点双连通分量包含哪些点
#include<bits/stdc++.h>
using namespace std;
const int N=5e5+10,M=2e6+10;
struct edge{
int x,y,pre;
}a[M*2];
int alen,last[N];
void ins(int x,int y)
{
a[++alen]={x,y,last[x]};
last[x]=alen;
}
int dfn[N],low[N],id,root;
vector<int> dcc[N];
int cnt;
stack<int> sta;
void tarjan(int x)
{
low[x]=dfn[x]=++id;
if(x==root&&!last[x]) return dcc[++cnt].push_back(x);
sta.push(x);
for(int k=last[x];k;k=a[k].pre)
{
int y=a[k].y;
if(!dfn[y])
{
tarjan(y);
low[x]=min(low[x],low[y]);
if(low[y]>=dfn[x])
{
cnt++;
int z;
do
{
z=sta.top();
sta.pop();
dcc[cnt].push_back(z);
} while(z!=y);
dcc[cnt].push_back(x);
}
}
else low[x]=min(low[x],dfn[y]);
}
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
if(x==y) continue;
ins(x,y),ins(y,x);
}
for(int i=1;i<=n;i++) if(!dfn[i]) root=i,tarjan(i);
printf("%d\n",cnt);//点双连通分量的数量
for(int i=1;i<=cnt;i++)
{
printf("%d ",(int)dcc[i].size());//当前点双连通分量的大小
for(auto j:dcc[i]) printf("%d ",j);//当前点双连通分量包含哪些点
puts("");
}
return 0;
}
有向图的tarjan
求出强连通分量的数量以及每个强连通分量的大小以及每个强连通分量包含哪些点
#include<bits/stdc++.h>
using namespace std;
const int N=1e4+10,M=1e5+10;
struct edge{
int x,y,pre;
}a[M];
int alen,last[N];
void ins(int x,int y)
{
a[++alen]={x,y,last[x]};
last[x]=alen;
}
int dfn[N],low[N],id;
vector<int> scc[N];
int cnt;
stack<int> sta;
bool v[N];
void tarjan(int x)
{
low[x]=dfn[x]=++id;
sta.push(x),v[x]=1;
for(int k=last[x];k;k=a[k].pre)
{
int y=a[k].y;
if(!dfn[y])
{
tarjan(y);
low[x]=min(low[x],low[y]);
}
else if(v[y]) low[x]=min(low[x],low[y]);
}
if(low[x]==dfn[x])
{
cnt++;
int y;
do
{
y=sta.top();
sta.pop(),v[y]=0;
scc[cnt].push_back(y);
}while(y!=x);
}
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
ins(x,y);
}
for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i);
printf("%d\n",cnt);//强连通分量的数量
for(int i=1;i<=cnt;i++)
{
printf("%d\n",scc[i].size());//当前强连通分量的大小
for(auto j:scc[i]) printf("%d ",j);//当前强连通分量包含哪些点
puts("");
}
return 0;
}
标签:tarjan,last,int,全家,alen,dfn,low
From: https://www.cnblogs.com/StarSky2008/p/17993008