poj 3352 Road Construction(边双连通)
题意:一个国家有N个城市,有M条路连接这N个城市,通过这些路任意两个城市都可以互达,现在为了游客的安全,决定重新修葺一下这些路,但是为了能方便游客,需要新修一些路,使得任意两城市间都有两条路。
思路:先求强连通分支,然后缩点,这样就形成了一个树,找到叶子节点ans,只要修(ans+1)/2条路就可以达到目的了。
代码:
View Code
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <iostream> #include <algorithm> #include <queue> #include <math.h> #include <stack> #define N 1005 using namespace std ; struct node { int e , next ; }p[2*N]; int dfn[N] , low[N] , out[N] , head[N] ; int n , m , cnt , id , num , ans ; //求强连通分支 void dfs( int x , int fa ) { dfn[x] = low[x] = ++id ; for ( int i = head[x] ; i != -1 ; i = p[i].next ) { int v = p[i].e ; if ( v != fa && !dfn[v] ) { dfs( v , x ) ; low[x] = min( low[x] , low[v]); if ( low[v] > dfn[x] ) { cnt++; } } else if ( v != fa && low[x] > dfn[v] ) low[x] = dfn[v] ; } } int main() { int i , j , x , y ; while ( scanf ( "%d%d" , &n , &m ) != EOF ) { //建图 memset( head , -1 , sizeof( head )) ; num = 0 ; for ( i = 1 ; i <= m ; i++ ) { scanf ( "%d%d" , &x , &y ) ; p[num].e = y ; p[num].next = head[x] ; head[x] = num++ ; p[num].e = x ; p[num].next = head[y] ; head[y] = num++ ; } //初始化 cnt = id = ans = 0 ; memset( out , 0 , sizeof ( out )) ; //缩点 dfs ( 1 , -1 ) ; //找叶子节点,度为1的为叶子节点 for ( i = 1 ; i <= n ; i++ ) { for ( j = head[i] ; j != -1 ; j = p[j].next ) { int v = p[j].e ; if ( low[i] != low[v] ) { out[low[i]]++ ; } } } for ( i = 1 ; i <= n ; i++) if ( out[i] == 1 ) ans++ ; printf ( "%d\n" , ( ans + 1 ) / 2 ) ; } return 0 ; }