题目大意:在一个小岛上,有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