边双连通分支
来源:互联网 发布:孤岛惊魂4优化怎么样 编辑:程序博客网 时间:2024/05/17 03:23
/*求边双连通分支:跑一遍求割点与桥的Tarjan得到该图的割点和桥,去掉桥,其余连通分支就是边连通分支了,边连通分支数是桥数+1。 边连通分支就是去掉最少两条边才能将该图划分为两个部分的图,桥就是一个图被去掉一条边就能变成两个子图的那一条边, 构造边双连通分支: 把双连通子图收缩为一个点,形成一个树,需要加边数量是(leaf+1)/ 2 。即不断把最近公共祖先最远的两个叶节点连接一条边 *///poj3177#include<iostream>#include<cstdio>#include<cstring>#include<algorithm> #include<map>using namespace std ;const int maxn = 5000 + 10 ;const int maxm = 20000 + 10 ;struct Edge{ int to , next ; //该边是否为桥 bool cut ;}edge[maxm];int head[maxn] , tot ;//Low[u]表示u所能追溯到的在栈中最早的节点,该Low数组和求割点与桥的Low数组定义不一样 int Low[maxn] , DFN[maxn] , Stack[maxn] , Belong[maxn] ;int Index , top ;//边双连通块数 int block ;bool Instack[maxn] ;//桥的数目 int bridge ;void addedge( int u , int v){ edge[tot].to = v ;edge[tot].next = head[u] ;edge[tot].cut = false ; head[u] = tot ++ ;}void Tarjan( int u , int pre){ int v ; Low[u] = DFN[u] = ++ Index ; Stack[top ++] = u ; Instack[u] = true ; for( int i = head[u] ; i != -1 ;i = edge[i].next ){ v = edge[i].to ; if( v == pre) continue ; //树枝边 if( !DFN[v ]){ //回溯从叶子结点开始处理,一直到根节点 Tarjan( v , u ) ; //对于树枝边(u,v),修改low[u]之前一定有何v相连的回向边修改了 Low[v],造成v的Low数值变小 if( Low[u] > Low[v] ) Low[u] = Low[v] ; //桥边,回溯过后v所能追溯到的标号最小的节点依旧比u的编号大,这时Low[v] = DFN[v] ; if( Low[v] > DFN[u]){ bridge ++ ; edge[i].cut = true ; edge[i ^ 1].cut = true ; } } //(u,v)回向边,修改u所能追溯到的编号最小的节点 else if( Instack[v] && Low[u] > DFN[v]) Low[u] = DFN[v] ; } //u节点是该连通分量的根节点 if( Low[u] == DFN[u]){ block ++ ; do{ v = Stack[ -- top ] ; Instack[v] = false ; Belong[v] = block ; } while( v != u ) ; }}void ini(){ tot = 0 ; memset( head , -1 , sizeof( head ) ) ;} //缩点后形成树,每个点的度数 int du[maxn] ;void solve( int n ){ memset( DFN , 0 ,sizeof( DFN )) ; memset( Instack , false , sizeof( Instack )) ; Index = top = block = 0 ; Tarjan( 1 , 0 ) ; int ans = 0 ; memset( du , 0 , sizeof( du )) ; for(int i = 1 ;i<=n ;i++){ for(int j = head[i] ;j!=-1 ; j=edge[j].next ) if( edge[j].cut ) du[Belong [i]] ++; } for(int i = 1 ;i<=block ; i++) if( du [i] == 1) ans ++; printf("%d\n" , ( ans + 1) / 2 ) ;}int main(){ int n , m ; int u , v ; while( scanf("%d%d" , & n , & m ) == 2){ ini() ; while( m -- ){ scanf("%d%d" , &u , & v ) ; addedge( u , v ) ; addedge( v , u ) ; } solve( n ) ; }}
阅读全文
0 0
- 边双连通分支
- poj 3177 边的双连通分支
- 割点、割边、双连通分支
- POJ 3177 & 3352 边双连通分支
- 割点、割边、双连通分支
- 双连通分支
- Tarjan算法求割,桥,块(点双连通分支),边双连通分支总结
- 求无向连通图边双连通分支
- 双连通分支 POJ 3177 3352
- 双连通分支与桥 POJ 3694
- 寻找双连通分支C语言
- 割点,桥,双连通分支
- POJ-3177-Redundant Paths【双连通分支】
- 边双连通分量
- 图的割点、桥与双连通分支
- 图的割点、桥与双连通分支
- 图的割点、桥与双连通分支
- 图的割点、桥与双连通分支
- git 406
- lua中常用库函数汇总
- java 通过poi 读取Excel 写入sqlser mysql
- JS windows.open打开窗口并居中,且调用完执行colse关闭方法,父窗口打开,子窗口执行,然后执行关闭
- 获取当前的格林尼治时间
- 边双连通分支
- 7月31日云栖精选夜读:金融安全资讯精选 2017年第一期:云战略下的安全思维转型与新认知
- java 基础
- Codeforces Round #427 (Div. 2)-B. The number on the board
- 一个类中的成员变量,局部变量,成员方法,构造函数。
- ImageView的scaleType属性
- JAVAFX2 如何在FXML获得ComboBox对象
- Vue实例的生命周期
- apache ant实现邮件发送