边双连通分支

来源:互联网 发布:孤岛惊魂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 ) ;    }}
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 老滚5视角锁死了怎么办 苹果描述文件没有了怎么办 苹果6s发热严重怎么办 苹果6s发烫严重怎么办 手机型号不适配全军出击怎么办? 苹果5版本过低怎么办 在泰国买到假货怎么办 在泰国旅游遇到危险该怎么办? 拾到小米手环怎么办 苹果充电打游戏触点怎么办 衣服上金属锈了怎么办 光之子门锁住了怎么办 挖到金矿石了该怎么办 邻居是精神病扔石头怎么办 汽车保养手册丢了怎么办 五号电池没电了怎么办 电脑打印时显示脱机怎么办 博新计划两年后怎么办 门帘粘扣老是掉怎么办 魔术粘贴带双面背胶不粘了怎么办 斜挎包包磨衣服怎么办 电脑ip被别人知道了怎么办 西乐葆不止痛了怎么办 家里鸽子多捣蛋的不行怎么办 联璧倒闭了理财钱怎么办 众筹平台雷了怎么办 App理财无法提现怎么办 喝咖啡喝的心慌怎么办 睾丸被用力捏破流血怎么办 足球大师球队声望过高怎么办 fm17买了好多球员怎么办 fm2018电脑适应了战术怎么办 家纺摆放跑色怎么办 买的t恤太小了怎么办? 汽车全包围脚垫翘边怎么办 针织衣服线跑了怎么办 老板跟老板娘吵架我应该怎么办 偷看老板娘洗澡被发现怎么办? 幽浮2人挂了怎么办 蜻蜓fm业务扣费怎么办 退出键退不到主页面怎么办