poj 3352 Road Construction 缩点

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

题目大意就是求添加多少条边可以构成双连通图,利用了缩点,由于这里不会出现重边所以就简单的利用了low数组最终的标记数字,相同的为一个连通分量,不通说明不在一个连通分量 进行统计,也就是求缩点后剩余的点构成多少个节点的树(num),然后要加的边就是(num+1)/2;

 关于有重边的情况稍后是再做此类题。

View Code
 1 #include <iostream>
2 #include <cstring>
3 #include <cstdlib>
4 #include <cstdio>
5 #include <vector>
6 using namespace std;
7 const int Max=1010;
8 int top[Max],edge[Max][Max];//memset(top,0,sizeof(top));
9 int dfsNum[Max],dfsnum;//memset(dfsNum,0,sizeof(dfsNum)),dfsNum=1;
10 int low[Max];
11 int degree[Max];
12 int ans;
13
14 void tarjan(int a,int fa) //fa是为了避免重复判
15 {
16 dfsNum[a]=low[a]=++dfsnum;
17 for(int i=0;i<top[a];i++)
18 {
19 if(edge[a][i]!=fa)
20 {
21 if(dfsNum[edge[a][i]]==0)//没有被访问过
22 {
23 tarjan(edge[a][i],a);
24 if(low[a]>low[edge[a][i]])
25 low[a]=low[edge[a][i]];
26 }
27 else //被访问过 这里跟有向图有个细微的区别 没有vist标记数组
28 {
29 if(low[a]>dfsNum[edge[a][i]])
30 low[a]=dfsNum[edge[a][i]];
31 }
32 }
33 }
34 }
35
36 int solve(int n)
37 {
38 int i,j;
39 int a,b;
40 for(i=1;i<=n;i++)
41 {
42 a=i;
43 for(j=0;j<top[i];j++)
44 {
45 b=edge[a][j];
46 if(low[a]!=low[b])
47 {
48 degree[low[a]]++;
49 degree[low[b]]++;
50 }
51 }
52 }
53 int leaves=0;
54 for(i=1;i<=n;i++)
55 {
56 if(degree[i]==2)
57 {
58 leaves++;
59 }
60 }
61 return (leaves+1)/2;
62 }
63
64 int main()
65 {
66 int n,m;
67 int i,a,b;
68 while(scanf("%d %d",&n,&m)!=EOF)
69 {
70 memset(top,0,sizeof(top));
71 memset(degree,0,sizeof(degree));
72 for(i=0;i<m;i++)
73 {
74 scanf("%d %d",&a,&b);
75 edge[a][top[a]++]=b;
76 edge[b][top[b]++]=a;
77 }
78
79 memset(dfsNum,0,sizeof(dfsNum));
80 dfsnum=0;
81
82 tarjan(1,-1);
83 ans=solve(n);
84 printf("%d\n",ans);
85 }
86 return 0;
87 }

 

posted @ 2012-04-01 19:55  我们一直在努力  阅读(183)  评论(0编辑  收藏  举报