poj 3352(边双连通分量)

题目链接:http://poj.org/problem?id=3352

思路:可以求出所有的桥,把桥删掉。然后把所有的连通分支求出来,显然这些连通分支就是原图中的双连通分支。把它们缩成点,然后添上刚才删去的桥,就构成了一棵树。在树上添边使得树变成一个双连通分支即可,这里我们可以直接统计缩点后的叶子节点个数即可,从而要加的边数即为(叶子节点个数+1)/2.

 1 #include<iostream>

 2 #include<cstdio>

 3 #include<cstring>

 4 #include<algorithm>

 5 #include<stack>

 6 #include<queue>

 7 #include<vector>

 8 using namespace std;

 9 #define MAXN 2222

10 

11 stack<int>S;

12 vector<int>map[MAXN];

13 

14 int low[MAXN],dfn[MAXN];

15 int color[MAXN];

16 bool mark[MAXN];

17 int degree[MAXN];

18 int n,m,cnt,_count;

19 

20 void Tarjan(int u,int father)

21 {

22     low[u]=dfn[u]=++cnt;

23     mark[u]=true;

24     S.push(u);

25     for(int i=0;i<map[u].size();i++){

26         int v=map[u][i];

27         if(v==father)continue;

28         if(dfn[v]==0){

29             Tarjan(v,u);

30             low[u]=min(low[u],low[v]);

31         }else if(mark[v]){

32             low[u]=min(low[u],dfn[v]);

33         }

34     }

35     if(low[u]==dfn[u]){

36         int v;

37         _count++;

38         do{

39             v=S.top();

40             S.pop();

41             mark[v]=false;

42             color[v]=_count;

43         }while(u!=v);

44     }

45 }

46 

47 int main()

48 {

49     int u,v;

50     while(~scanf("%d%d",&n,&m)){

51         for(int i=1;i<=n;i++)map[i].clear();

52         memset(low,0,sizeof(low));

53         memset(dfn,0,sizeof(dfn));

54         memset(mark,false,sizeof(mark));

55         memset(degree,0,sizeof(degree));

56         memset(color,0,sizeof(color));

57         cnt=_count=0;

58         while(m--){

59             scanf("%d%d",&u,&v);

60             map[u].push_back(v);

61             map[v].push_back(u);

62         }

63         for(int i=1;i<=n;i++){

64             if(dfn[i]==0)Tarjan(i,-1);

65         }

66         for(int i=1;i<=n;i++){

67             for(int j=0;j<map[i].size();j++){

68                 if(color[i]!=color[map[i][j]]){

69                     degree[color[i]]++;

70                 }

71             }

72         }

73         cnt=0;

74         for(int i=1;i<=_count;i++){

75             if(degree[i]==1)cnt++;

76         }

77         printf("%d\n",(cnt+1)/2);

78     }

79     return 0;

80 }

81             

82         

83             

84     

85             
View Code

 

你可能感兴趣的:(poj)