poj 1523 SPF 割点

缘起

日常浪费生命~ poj 1523 SPF

分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
给定一个连通无向图,网络的结点数<=1000,求出这个网络的所有割点编号,并求出若删去其中一个割点k后,对应
的,原网络会被分割为多少个连通分支

【输入】
多样例. 每个样例由多行构成. 每行两个正整数, 表示边.

【输出】


【样例输入】
1 2
5 4
3 1
3 2
3 4
3 5
0

1 2
2 3
3 4
4 5
5 1
0

1 2
2 3
3 4
4 6
6 3
2 5
5 1
0

0

【样例输出】
Network #1
SPF node 3 leaves 2 subnets

Network #2
No SPF nodes

Network #3
SPF node 2 leaves 2 subnets
SPF node 3 leaves 2 subnets

【限制】
1s

求所有割点的模板在【1】中已经介绍过了. 本题在求所有割点之外还要问每个割点去掉之后原无向连通图被分割成几个连通分支(注意, 是连通分支,而不是bcc).

这其实很好办——毕竟网络节点数<=1000. 完全可以tarjan求出所有割点之后, 遍历考察每个割点. 然后去掉这个割点之后dfs原网络. 算出连通分支的个数即可(dfs求无向图的连通分支的数量是常规桥段了).

本题处理输入输出较坑. 需要小心

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
//#include "stdafx.h"

#include <stdio.h>
#include <algorithm>
#include <string.h>
using namespace std;
//#define LOCAL

int head[1005], cnt, n, timestamp[1005], low[1005], t; // n是顶点数
bool v[1005],cut[1005];

struct Arc
{
int from, to, nxt;
}g[100005];

void addArc(int a,int b)
{
g[cnt].from = a, g[cnt].to = b, g[cnt].nxt = head[a];
head[a] = cnt++;
}

void dfs(int cur, int fa)
{
timestamp[cur] = low[cur] = ++t;
int child = 0;
for (int h = head[cur],to; ~h; h = g[h].nxt)
{
to = g[h].to;
if (!timestamp[to])
{
child++;
dfs(to, cur);
low[cur] = min(low[cur], low[to]);
if ((cur==1&&child>1) || (cur!=1&&low[to]>=timestamp[cur]))
{
cut[cur] = true;
}
}
else if (to!=fa)
{
low[cur] = min(low[cur], timestamp[to]);
}
}
}

void ddfs(int i) // dfs求无向图连通分支的个数
{
v[i] = true;
for (int h = head[i],to; ~h; h = g[h].nxt)
{
to = g[h].to;
if (!v[to])
{
ddfs(to);
}
}
}

int main() {

#ifdef LOCAL
freopen("d:\\data.in", "r", stdin);
//freopen("d:\\my.out", "w", stdout);
#endif
int a,b,kase = 0; // 边 a-b
while(scanf("%d", &a), a)
{
if (kase)
{
puts("");
}
printf("Network #%d\n",++kase);
memset(head, -1, sizeof(head)),cnt = 0;
memset(timestamp, 0, sizeof(timestamp)), memset(low, 0, sizeof(low)),memset(cut, 0, sizeof(cut)), t=0;
n = a;
scanf("%d", &b);
n = max(n, b);
addArc(a,b), addArc(b,a);
while(scanf("%d", &a),a)
{
n = max(n,a);
scanf("%d", &b);
n = max(n,b);
addArc(a,b), addArc(b,a);
} // 至此,读图完毕(本题输入输出有点坑~)
dfs(1,0); // 跑tarjan,求所有割点
int ans = 0;
for (int i = 1; i<=n;i++)
{
if (cut[i]) //i是割点
{
ans++;
}
}
if (!ans)
{
puts(" No SPF nodes");
}
else
{
for (int i = 1; i<=n;i++)
{
if (cut[i]) //i是割点, 就要开始跑dfs求无向图的连通分量的个数了
{
memset(v, 0, sizeof(v));
v[i] = true; // 割点不允许访问了(实现原网络去掉割点的效果)
ans = 0;
for (int j = 1;j<=n; j++) // dfs求无向图(因为去掉了割点,所以未必连通了)连通分支的个数
{
if (!v[j])
{
ans++;
ddfs(j);
}
}
printf(" SPF node %d leaves %d subnets\n",i,ans);
}
}
}
}
return 0;
}

ac情况

Status Accepted
Memory 140kB
Length 2072
Lang C++
Submitted 2019-09-09 10:13:09
Shared
RemoteRunId 20845022

参考

【1】https://yfsyfs.github.io/2019/09/08/poj-1144-Network-%E5%89%B2%E7%82%B9/