无向图 割点
来源:互联网 发布:马鞍山网络大学专升本 编辑:程序博客网 时间:2024/04/30 11:34
1.定义:
割点:某个点是割点当且仅当删除该点和与该点相关联的边后图变得不连通。
桥(割边):某条边是割边当且仅当删除该边后图变的不连通。
双连通分支:图G的所有子图G'中,如果G'是连通的,则称G'是双连通子图。如果G'不是任何一个连通子图的真子图,那么图G'是双连通分支。特别的,点双连通分支又叫做块。
2.求割点,桥
对原图进行深度优先搜索,会生成一颗深度优先搜索生成树。定义dfs[u]为u在深度优先搜索生成树中被遍历到的序号,low[u]为u或者他的子树中可以通过非父子边追溯到的最早结点。
那么一个顶点是割点,满足下列条件之一:
1).u是树根,u有两个或两个以上的分支;
2).u不是树根,(u,v)是树边且low[v]>=dfn[u]。
边(u,v)是桥,当且仅当low[v]>dfn[u],(u,v)是树边。
下面是自己总结了多人的模板后写的,自已的模板(我的风格的)
性质:low[]的值相等的点为同一个连通分量。
int root, cnt,son;
//
int vis[Max], dfn[Max], low[Max];
//
证明1:
假设DFS遍历的第一个节点v不是割点,那么则有low[v]=dfn[v]=1,继续对v的孩子节点u遍历,必然有low[u]>=dfn[v],按照第二条性质,则v是割点,但我们已经假设v不是割点。这是由于v是DFS遍历的起始节点,在遍历序列中v没有祖先节点,v的所有后继节点能追溯到最早的祖先节点最多也就是v了,不可能比v再早了,因此必须把DFS遍历的第一个节点v单独考虑,那么怎么判断v是不是割点呢?
例如上图,设v是DFS序列访问的第一个节点,对v的孩子节点u和u的所有孩子节点进行DFS遍历并标记为已经访问后,如果v的另一个孩子节点k没有被标记为已经访问,那么u和k之间一定不存在边,也就是说u和k之间的连通必然需要点v,因此如果v是DFS遍历的第一个节点,对v是否为割点的判断方法是:看v是不是有多个孩子,如果有则v是割点。
证明2:
如果v不是DFS遍历的第一个节点,那么对于v的所有后继节点来说,如果v不是割点(也就是如果删掉点v,剩下的图还是连通图),那么v的后继节点必然能追溯到DFS遍历序列中v的祖先节点,也就是v的后继节点中存在到达DFS序列中v的祖先的路径,因此当DFS回溯到v节点时对于v的所有后继节点u来说,都有low[u]<dfn[v]。
如果v是一个割点,对所有v的后继节点u进行DFS后,必然有low[u]>=dfn[v],这是因为,当遍历v并将其锁定后,到达v的祖先节点的路径已经被封死,v的后继节点必然不可能访问到v的祖先节点,因此,必然有low[u]>=dfn[v]。
#include "iostream"#include "vector"#include "fstream"using namespace std;std::vector<vector<int> > edge;std::vector<int> low;std::vector<int> depth;std::vector<bool> cut;std::vector<bool> visited;int vertexnum;int edgenum;void initialvector(){edge.resize(vertexnum);//路径数组low.resize(vertexnum,10000);//low[u]为u或者他的子树中可以通过非父子边追溯到的最早结点,low[]的值相等的点为同一个连通分量depth.resize(vertexnum);//结点在搜索树中的深度,有很多是使用时间编号cut.resize(vertexnum,false);//割点数组visited.resize(vertexnum,false);//记录遍历节点}void getData(){//获取数据ifstream in("data");in>>vertexnum>>edgenum;initialvector();int from,to;while(in>>from>>to){//无向图edge[from].push_back(to);edge[to].push_back(from);}}void dfs(int current,int parent,int dep){visited[current] = true;depth[current] = dep;low[current] = dep;int child = 0;for (std::vector<int>::iterator i = edge[current].begin(); i != edge[current].end(); ++i){if(*i != parent && visited[*i]){low[current] = min(low[current],depth[*i]);//不知道改为low[current] = min(low[current],low[*i]);可不可以}if(!visited[*i]){//遍历未访问节点dfs(*i,current,dep+1);child++;//记录孩子数low[current] = min(low[current],low[*i]);//更新current节点,此时current子节点的low值已经确定if((current == 0 && child > 1)||(current != 0 && low[*i] >= depth[current])){cut[current] = true;}//如果根结点有大于1个的儿子,那么根结点是割点||如果对于点u的某个儿子v,有low[v] >= dep[u],那么u就是一个割点}}}int main(int argc, char const *argv[]){getData(); dfs(0,0,0);for (int i = 0;i < cut.size();i++){if(cut[i]){cout<<i<<" ";}}cout<<endl;return 0;}
data:13 17
0 1
0 2
0 5
0 11
1 2
1 3
1 6
1 7
1 12
3 4
6 7
6 8
6 10
7 10
9 11
9 12
9 12
其中0->A,1->B,......
参考:
http://blog.csdn.net/cxllyg/article/details/7610265
http://blog.sina.com.cn/s/blog_691ce2b701017gdx.html
http://blog.csdn.net/xinghongduo/article/details/6202646
- 无向图 割点
- 无向图的割点算法
- 39.2 无向图的割点
- 无向图 割点模板
- 判断无向图中的割点
- 无向连通图的割点与割边
- 无向图关键点(dfs邻接阵),割点
- ZJU1311 Network - 无向图的割点
- 无向连通图的割点、桥
- 无向图的割点和桥
- 无向连通图的割点和桥
- 求解无向图的割点和桥
- 求无向图的割点和桥
- 无向图的割点(关节点)
- POJ2117.Electricity——无向图的割点
- POJ1144.Network——无向图的割点
- 求无向连通图的割点
- 求无向连通图的割点
- 2013年4月26日 home键
- Linux中( ) 与{ } 的区别
- 网络之ASIHttpRequest和SBJson简单使用 .
- win7资源管理器经常崩溃shellext.dll_unloaded
- 跳槽·跳蚤
- 无向图 割点
- Web Audio API简易入门教程
- Linux中awk使用大全
- 在Service中新开线程和直接新开线程的区别与意义
- define和const区别
- Linux中awk后接数字1含义
- 记录一下Hive中间和最终结果压缩
- adb shell dumpsys
- Linux中AWK获取xml文件节点值