tajan的dfs树系列算法:
求解割点,桥,强连通分量,点双联通分量,边双联通分量;
tajan是一个dfs,把一个图变成一个dfs树结构,
dfs树结构,本质是通过一个没有任何要求的dfs把图的边分为:树边和返祖边:
- 树边:dfs中父节点与其未曾遍历过的子节点间的边,
- 返祖边:父节点与他的dfs中曾作为该父节点祖先的子节点间的边
在有向图中,除了这二种边外,还有父节点与曾遍历过的子节点间的边,然而这个子节点不是父节点的祖先,
然而这种边在tarjan中没有意义,我们所求的东西用不上她们
伪代码:
深搜(点now){
更新点now——
dfs序(dfn)与目前可到dfn最小祖先的dfn(low),标记已经遍历(vis),确认now将是他后继递归的点的祖先(instk),其他
for(以now为起点的所有边)
if(边终点to未遍历)
深搜(to),low[now]=min(low[now],low[to])
else
if(instk[to]为真)//无向图可以不存在这个
low[now]=min(low[now],dfn[to])
更新instk[now]为假
}
求(无向图)割点,桥:
割点:无向图中,删除之可改变图的连通性的点
两种:
- 两个点双连通分量的公共点
- 两个点双连通分量直接存在一条边连接,这条边的两端点
桥:无向图中,删除之可改变图的连通性的边
一种:
两个边双连通分量间的连边;
求法:
割点:这个点儿子中有至少一个的low小于这个点的dfn
桥:该边终点的low=dfn
例题:
code:
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; int n,m; struct ss{ int to,next; }e[200010]; struct Cl{ int u,v; }Cedge[200010]; int first[20010],num; int pnu,enu; int Cpoint[20010]; int dfn[20010],low[20010],vis[20010]; bool cmp(Cl a,Cl b){ return a.u<b.u||(a.u==b.u&&a.v<b.v); } void Input(); void work(); void Output(); void build(int ,int ); void Init(); void dfs_1(int ,int ); void dfs_2(int ,int ); int main() { Input(); work(); Output(); return 0; } void Input(){ int i,j,k; scanf("%d%d",&n,&m); for(i=1;i<=m;i++){ scanf("%d%d",&j,&k); build(j,k);build(k,j); } } void work(){ pnu=0;enu=0; Init(); dfs_1(1,0); Init(); dfs_2(1,0); } void Output(){ int i; for(i=1;i<=enu;i++) if(Cedge[i].u>Cedge[i].v) swap(Cedge[i].u,Cedge[i].v); sort(Cpoint+1,Cpoint+pnu+1); sort(Cedge+1,Cedge+enu+1,cmp); for(i=1;i<=pnu;i++) printf("%d ",Cpoint[i]); if(pnu==0) printf("Null"); printf("\n"); for(i=1;i<=enu;i++) printf("%d %d\n",Cedge[i].u,Cedge[i].v); } void build(int f,int t){ e[++num].next=first[f]; e[num].to=t; first[f]=num; } void Init(){ memset(dfn,0,sizeof(dfn)); memset(low,0,sizeof(low)); memset(vis,0,sizeof(vis)); num=0; } void dfs_1(int now,int fa){ int i,p=0; if(now!=1)p=1; dfn[now]=low[now]=++num;vis[now]=1; for(i=first[now];i;i=e[i].next) if(e[i].to!=fa){ if(!vis[e[i].to]){ dfs_1(e[i].to,now); if(low[e[i].to]>=dfn[now])p++; if(low[now]>low[e[i].to]) low[now]=low[e[i].to]; } else if(low[now]>dfn[e[i].to]) low[now]=dfn[e[i].to]; } if(p>=2) Cpoint[++pnu]=now; } void dfs_2(int now,int fa){ int i; dfn[now]=low[now]=++num;vis[now]=1; for(i=first[now];i;i=e[i].next) if(e[i].to!=fa){ if(!vis[e[i].to]){ dfs_2(e[i].to,now); if(low[now]>low[e[i].to]) low[now]=low[e[i].to]; if(low[e[i].to]>dfn[now]) Cedge[++enu].u=now,Cedge[enu].v=e[i].to; } else if(low[now]>dfn[e[i].to]) low[now]=dfn[e[i].to]; } }