pku3352 (边)双连通分量

Road Construction

题目大意:在一个小岛上,有n个景点,r条道路,经常由于有的路需要修理,影响了旅客的观光。问:如果修理任意一条路的时候都不影响任意两个景点的连通,至少还需要多少条路。

分析:以景点为节点,道路为边,建图后,去掉任何一条边,都不影响整体的连通性,说明此图的连通度 >= 2,正好是双连通的性质,如果去掉某条边,图的连通分支增加了,则这条边称为桥,这道题就可以用dfs找到这些桥,去掉桥,找到所有分支,判断每个分支的度,如果 deg = 1,为叶子结点,找到所有叶子节点个数leaf,输出(leaf + 1) / 2即可。

这道题和pku3177完全一样,只改动两个数组长度的宏定义,就能过,还0ms。

 

代码
   
     
1 #include < stdio.h >
2 #include < string .h >
3   #define MM 2004
4   #define NN 1004
5
6 typedef struct node{
7 int v, vis;
8 struct node * nxt, * op;
9 }NODE;
10 NODE edg[MM];
11 NODE * link[NN];
12 NODE * par[NN];
13
14 int n, idx, bCnt, time;
15 int dfn[NN];
16 int low[NN];
17 int bel[NN];
18 int deg[NN];
19
20 int Min( int a, int b){
21 return a < b ? a : b;
22 }
23 void Add( int u, int v){ // 由于边是无向的,所以加双向边
24 edg[idx].v = v;
25 edg[idx].vis = 0 ;
26 edg[idx].nxt = link[u];
27 edg[idx].op = edg + idx + 1 ;
28 link[u] = edg + idx ++ ;
29 edg[idx].v = u;
30 edg[idx].vis = 0 ;
31 edg[idx].nxt = link[v];
32 edg[idx].op = edg + idx - 1 ;
33 link[v] = edg + idx ++ ;
34 }
35
36 void dfs( int u){ // 建树
37 int v;
38 dfn[u] = low[u] = ++ time;
39 for (NODE * p = link[u]; p; p = p -> nxt){
40 v = p -> v;
41 if (p -> vis) continue ;
42 p -> vis = p -> op -> vis = 1 ;
43 if ( ! dfn[v]){
44 par[v] = p -> op;
45 dfs(v);
46 low[u] = Min(low[u], low[v]);
47 } else {
48 low[u] = Min(low[u], dfn[v]);
49 }
50 }
51 }
52
53 void Part( int u){ // 将u所在连通分支中所有点都归入分支bCnt
54 int v;
55 bel[u] = bCnt;
56 for (NODE * p = link[u]; p; p = p -> nxt){
57 v = p -> v;
58 if (p -> vis && ! bel[v]){
59 Part(v);
60 }
61 }
62 }
63 void Solve(){
64 int i, u, v, leaf;
65 time = 0 ;
66 memset(dfn, 0 , sizeof (dfn));
67 memset(par, 0 , sizeof (par));
68 dfs( 1 );
69 for (v = 2 ; v <= n; v ++ ){ // 删除桥
70 u = (par[v]) -> v;
71 if (dfn[u] < low[v]){
72 par[v] -> vis = par[v] -> op -> vis = 0 ;
73 }
74 }
75 bCnt = 0 ;
76 memset(bel, 0 , sizeof (bel));
77 for (u = 1 ; u <= n; u ++ ){ // 节点归类,分支划分
78 if ( ! bel[u]){
79 bCnt ++ ;
80 Part(u);
81 }
82 }
83 memset(deg, 0 , sizeof (deg));
84 for (u = 1 ; u <= n; u ++ ){ // 查找叶子节点
85 for (NODE * p = link[u]; p; p = p -> nxt){
86 v = p -> v;
87 if (bel[u] != bel[v]){
88 deg[bel[u]] ++ ; // 易错点,这里是deg[bel[u]]++,而不是deg[u]
89 }
90 }
91 }
92
93 leaf = 0 ;
94 for (i = 1 ; i <= bCnt; i ++ ){
95 if (deg[i] == 1 ) leaf ++ ;
96 }
97 if (leaf == 1 ) puts( " 0 " ); // 如果是个双连通图,就不用加边了
98 else printf( " %d\n " , (leaf + 1 ) / 2 );
99 }
100 int main()
101 {
102 int r, u, v;
103 scanf( " %d%d " , & n, & r);
104 memset(link, 0 , sizeof (link));
105 idx = 0 ;
106 while (r -- ){
107 scanf( " %d%d " , & u, & v);
108 Add(u, v);
109 }
110 Solve();
111 return 0 ;
112 }
113

 

你可能感兴趣的:(pku)