2015-08-10 00:19:19
总结:割顶 / 桥的 Tarjan 求法学过很久了。在小结一下SCL吧~加入 vis[ ] 数组是为了考虑重边!
(1)割顶:连通的无向图中,去掉该点无向图不再连通。
void Init(){ memset(first,-1,sizeof(first)); ecnt = tot = 0; } void Dfs(int p,int pre){ low[p] = dfn[p] = ++tot; int son = 0; for(int i = first[p]; ~i; i = e[i].next){ if(vis[i]) continue; vis[i] = vis[i ^ 1] = true; int v = e[i].v; if(!dfn[v]){ ++son; Dfs(v,p); low[p] = min(low[p],low[v]); if(low[v] >= dfn[p]) iscut[p] = 1; //割顶 } else low[p] = min(low[p],dfn[v]); } if(pre < 0 && son == 1) iscut[p] = 0; } bool Tarjan(){ memset(low,0,sizeof(low)); memset(dfn,0,sizeof(dfn)); memset(iscut,0,sizeof(iscut)); memset(vis,false,sizeof(vis)); Dfs(1,-1); //如果图不止一块那么初始显然不连通 //检查是否所有点的 dfn 都非零了 for(int i = 1; i <= N; ++i) if(dfn[i] == 0) return false; return true; }
(2)桥:连通的无向图中,去掉该边后无向图不再连通。
void Init(){ memset(first,-1,sizeof(first)); ecnt = tot = 0; } void Dfs(int p,int pre){ dfn[p] = low[p] = ++tot; for(int i = first[p]; ~i; i = e[i].next){ int v = e[i].v; if(vis[i]) continue; vis[i] = vis[i ^ 1] = true; if(!dfn[v]){ Dfs(v,p); low[p] = min(low[p],low[v]); if(low[v] > dfn[p]) bg[i] = bg[i ^ 1] = true; } else low[p] = min(low[p],dfn[v]); } } bool Tarjan(){ memset(dfn,0,sizeof(dfn)); memset(low,0,sizeof(low)); memset(bg,false,sizeof(bg)); memset(vis,false,sizeof(vis)); Dfs(1,-1); //如果图中不止一块那么初始显然不连通 //检查是否所有点的dfn都清零了 for(int i = 1; i <= N; ++i) if(dfn[i] == 0) return false; return true; }