一、基本概念
1、割点:无向连通图中,如果删除某点后,图变成不连通,则称改点为割点。
2、桥:无向连通图中,如果去掉某条边后,整张无向图会分成两部分(即整张图不连通),这样的一条边成为桥。
3、点双连通分量:无割点的极大连通子图
任意两点间都有?至少两条不不经过相同边的路径
4、边双连通分量:无割边的极大连通子图
任意两点间都有?至少两条(除起点和终点外)不不经过相同点的路径
二、tarjan求割点
1)当前节点为树根时,成为割点的条件是“要有多于一个子树”(如果只有一棵子树,去掉这个点也没有影响,如果有两颗子树,去掉这个点,两颗子树就不连通了)
2)当前节点不是树根的时候,条件是“low [ v ] >= dfn [ u ] ”,也就是在u之后遍历的点,能够向上翻,最多到u。(如果能翻到u的上方,那就有环了,去掉u之后,图仍然连通。)所以,保证v向上翻最多到u才可以
#include<cstdio> #include<algorithm> using namespace std; inline int read() { int sum = 0,p = 1; char ch = getchar(); while(ch < ‘0‘ || ch > ‘9‘) { if(ch == ‘-‘) p = -1; ch = getchar(); } while(ch >= ‘0‘ && ch <= ‘9‘) { (sum *= 10) += ch - ‘0‘; ch = getchar(); } return sum * p; } const int maxn = 20005,maxm = 100005; int n,m,tot; int dfn[maxn],low[maxn],tim; int cnt,head[maxn]; struct edge { int nxt,to; }e[maxm * 2]; bool mrk[maxn]; void add(int x,int y) { e[++cnt].nxt = head[x]; e[cnt].to = y; head[x] = cnt; } void tarjan(int u,int fa) { dfn[u] = low[u] = ++tim; int child = 0; for(int i = head[u];i;i = e[i].nxt) { int v = e[i].to; if(!dfn[v]) { tarjan(v,fa); low[u] = min(low[u],low[v]); if(low[v] >= dfn[u] && u != fa) mrk[u] = true; if(u == fa) child++; } low[u] = min(low[u],dfn[v]); } if(child >= 2 && u == fa) mrk[u] = true; } int main() { n = read(),m = read(); for(int i = 1;i <= m;i++) { int x = read(),y = read(); add(x,y); add(y,x); } for(int i = 1;i <= n;i++) if(!dfn[i]) tarjan(i,i); for(int i = 1;i <= n;i++) if(mrk[i]) tot++; printf("%d\n",tot); for(int i = 1;i <= n;i++) if(mrk[i]) printf("%d ",i); return 0; }
原文地址:https://www.cnblogs.com/darlingroot/p/11221478.html
时间: 2024-10-09 00:03:29