//强联通
struct edge{
int to,next,num; //增设num为判重边
}e[M];
int scc,hea,tim;
int low[N],dfs[N],tr[N],sccno[N];
int head[N],o;//记得初始化
void add(int x,int y,int m)
{
e[o].to=y;
e[o].next=head[x];
e[o].num=m;
head[x]=o++;
}
scanf("%d%d",&x,&y);{add(x,y,i); add(y,x,i);}
void tarjandfs(int now,int from)
{ int v;
tr[++hea]=now; in[now]=1;
dfs[now]=++tim; low[now]=dfs[now];
for (int k=head[now];k!=-1;k=e[k].next)
{ v=e[k].to;
if (e[k].num==from) continue; //imp!
if (dfs[v]==0)//生成树的边
{tarjandfs(v,e[k].num); low[now]=min(low[now],low[v]);
}
else if (in[v])//回边
low[now]=min(low[now],dfs[v]);
}
/*具体剥离出每个强连通分量,一般用于一般有向图*/
if(low[now]==dfs[now])
{ int i;
scc++;
do{i=tr[hea--]; sccno[i]=scc; in[i]=0;}while(i!=now);
}
}
//因为有向图除了树枝边、回边还有交叉边,所以in数组不可少。而无向图没有交叉边(除了树枝边就是回边),故可以直接else而省去in数组。
主函数:
tcc=tim=hea=0;memset(dfs,0,sizeof(dfs));memset(low,0,sizeof(low));memset(in,0,sizeof(in));//初始化
tarjandfs(1,-1);//前提:题目保证是个连通图(弱连通)
//否则要for (i=1;i<=n;i++) if (!dfs[i]) tarjandfs(i,-1);
1.求割边
if (dfs[now]<low[v]&&e[k].num==1) an[ans++]=e[k].id;
2.去掉关节点u,将连通图分成几个连通分量?
(1).u是关节点,几个儿子几个分量(2)不是根节点,d个子女w,满足low[w]>=dfn[u],为d+1个分量
具体实现:for (i=1;i<=max;i++) ans[i]=1; ans[1]=0;
//ans[i]=1代表i上头的那一部分(有根的那部分)
//&&在low[now]=min(low[now],low[v]);这句话后面加if (dfs[u]<=low[w]) ans[u]++;
//双联通
//代码1
int dfs[N],low[N],bccno[N];//3个数组均memset为0
int n,m;
int tim,bcc;
struct edge{
int u,v;
edge(int x=0,int y=0):u(x),v(y){}
}e[M];
vector<int > BCC[N],g[N];
bool iscut[N];//初始化为0
stack<edge> S;
int tarjandfs(int u,int from=-1)
{ int lowu=dfs[u]=++tim;
int child=0;
for (int i=0;i<g[u].size();i++)
{ int v=g[u][i];
edge e=edge(u,v);
if (!dfs[v])
{
S.push(e);
child++;
int lowv=tarjandfs(v,u);
lowu=min(lowu,lowv);
if (lowv>=dfs[u])
{ iscut[u]=1;
bcc++; BCC[bcc].clear();
while (1)
{
edge x=S.top(); S.pop();
if (bccno[x.u]!=bcc) {BCC[bcc].pb(x.u);bccno[x.u]=bcc;}
if (bccno[x.v]!=bcc) {BCC[bcc].pb(x.v);bccno[x.v]=bcc;}
if (x.u==u&&x.v==v) break;
}
}
}
else if (dfs[v]<dfs[u]&&v!=from){
S.push(e);
lowu=min(lowu,dfs[v]);
}
}
if (from<0&&child==1) iscut[u]=0;
return lowu;
}
//bcc=tim=0;
//memset(iscut,0,sizeof(iscut));
//memset(dfs,0,sizeof(dfs));
//memset(low,0,sizeof(low));
//memset(bccno,0,sizeof(bccno));
//for (int i=1;i<=n;i++)if (!dfs[i]) tarjandfs(i,-1);
//S保证第一组数据前是empty的
//双联通
//代码2
int dfs[N],low[N],bccno[N];//3个数组均memset为0
int tr[N];
int n,m;
int tim,bcc,hea;
vector<int > BCC[N],g[N];
bool iscut[N],vv[N];//2个初始化为0
void tarjandfs(int u,int from=-1)
{ low[u]=dfs[u]=++tim;
tr[++hea]=u; vv[u]=1;
int child=0;
for (int i=0;i<g[u].size();i++)
{ int v=g[u][i];
if (v==from) continue;
if (!dfs[v])
{ tarjandfs(v,u);child++;
low[u]=min(low[u],low[v]);
if (dfs[u]<=low[v])
{ iscut[u]=1;
int x;
bcc++;BCC[bcc].clear();
do{x=tr[hea--]; bccno[x]=bcc; BCC[bcc].pb(x); vv[x]=0; }while(x!=v);
BCC[bcc].pb(u);
}
}
else if (vv[v])
low[u]=min(low[u],dfs[v]);
}
if (from<0&&child==1) iscut[u]=0;
}
//bcc=tim=hea=0;
//memset(dfs,0,sizeof(dfs));
//memset(low,0,sizeof(low));
//memset(bccno,0,sizeof(bccno));
//memset(vv,0,sizeof(vv));
//memset(iscut,0,sizeof(iscut));
//for (int i=1;i<=n;i++)if (!dfs[i]) tarjandfs(i,-1);