【要求】给定一个无向图,找出图中的割点个桥
【说在前面】看了这么多,想入门理解的话真心推荐“听雨草堂”这一篇,结合模板以及各数组表示的含义看,至少把我看懂了。 模板我没用她的,用的是上交红书的模板,反正都一样的东西;
【几个定义】
- DFS搜索树:用DFS对图进行遍历时,按照遍历次序的不同,我们可以得到一棵DFS搜索树,如图(b)所示。
- 树边:(或称父子边),在搜索树中的实线所示,可理解为在DFS过程中访问未访问节点时所经过的边。
- 回边:(或称返祖边、后向边),在搜索树中的虚线所示,可理解为在DFS过程中遇到已访问节点时所经过的边。
【重点】基于DFS的算法 ---> Tarjan
- 对根节点u,若其有两棵或两棵以上的子树,则该根结点u为割点;
- 对非叶子节点u(非根节点),若其子树的节点均没有指向u的祖先节点的回边,说明删除u之后,根结点与u的子树的节点不再连通;则节点u为割点。
cur是割点的条件:①cur是根且有大于一个儿子; ②cur不是根且cur有一个儿子v使low[v] >= dfn[cur];、
(cur, i)是桥的条件:low[i] > dfn[cur];
【难点】 对于dfn[MAX_V]与low[MAX_V]数组的理解与模拟其实现过程;
int dfn[MAX_V]; //结点v被访问时的深度 int low[MAX_V]; //结点v可以到达的访问时间最早的祖先的深度
详细示例见原博主;
【模板】
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<vector> 5 #include<iostream> 6 using namespace std; 7 const int MAX_V = 1000; 8 const int MAX_E = 1000000; 9 10 int vis[MAX_V]; //结点v当前访问状态,0表示未访问,1表示在栈中,2表示已经访问过 11 int dfn[MAX_V]; //结点v被访问时的深度 12 int low[MAX_V]; //结点v可以到达的访问时间最早的祖先的深度 13 bool cut[MAX_V]; 14 bool bridge[MAX_V][MAX_V]; 15 //cur是割点的条件:①cur是根且有大于一个儿子; ②cur不是根且cur有一个儿子v使low[v]>=dfn[cur]; 16 //(cur, i)是桥的条件:low[i] > dfn[cur]; 17 void cur_bridge(int cur, int father, int dep, int n) //vertex: 0~n-1 18 { 19 vis[cur] = 1; 20 dfn[cur] = dep; 21 low[cur] = dep; 22 int children = 0; 23 for(int i = 0; i < n; i++) 24 { 25 if(edge[cur][i]) //与当前节点相连的结点i 26 { 27 if(i != father && vis[i] == 1) //i在当前栈中,说明图中有一个环,用i的深度更新cur的low值; 28 { 29 if(dfn[i] < low[cur]) low[cur] = dfn[i]; //将结点cur可以到达的访问时间最早的祖先的深度更新为结点i被访问时的深度; 30 } 31 if(vis[i] == 0) //i没被访问过,递归访问节点i,并用i的可以到达的最早祖先来更新cur的low值; 32 { 33 cut_bridge(i, cur, dep+1, n); 34 children ++; 35 36 if(low[i] < low[cur]) low[cur] = low[i]; 37 if((father == -1 && children > 1) || (father == -1 && low[i] >= dfn[cur]) //判断割点 38 cut[cur] = true; 39 if(low[i] > dfn[cut]) bridge[cur][i] = bridge[i][cur] = true; //判断桥 40 } 41 } 42 } 43 vis[cur] = 2; 44 }
时间: 2024-10-13 01:38:02