-强连通分量-DFS- [洛谷 P4306][JSOI2010]连通数

题目描述

度量一个有向图恋情情况的一个指标是连通,指途中可达点对的个数。

下图的连通数是14

现在要你求出连通数

输入格式

输入数据第一行是图顶点的数量,一个正整数N。 接下来N行,每行N个字符。第i行第j列的1表示顶点i到j有边,0则表示无边。

输出格式

输出一行一个整数,表示该图的连通数。

输入样例

3
010
001
100

输出样例

9

说明

对于100%的数据,N不超过2000。

Solution

对于这道题,我们先将这个有向图缩点,然后在进行dfs就可以了

Code

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
124
125
126
127
128
129
130
131
132
133
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define MAXN 10010
namespace STman {
inline char gc(){
#ifdef ONLINE_JUDGE
static char now[1 << 16], *S, *T;
if (T == S) {T = (S = now) + fread(now, 1, 1 << 16, stdin); if (T == S) return EOF;}
return *S++;
#else
return getchar();
#endif
}
template <typename Tp>
inline void read(Tp &x) {
Tp f = 1;x = 0;
char k = gc();
while (k < '0' || k > '9') {if (k == '-') f = -1;k = gc();}
while (k >= '0' && k <= '9') {x = x * 10 + k - '0';k = gc();}
x = x * f;
}
template <typename Tp>
inline void write(Tp x) {
if (x < 0) putchar('-') , x = -x;
if (x > 9) write(x / 10);
putchar(x % 10 + '0');
}
template <typename Tp>
inline Tp max(Tp a , Tp b) {
if (a > b) return a;
else return b;
}
template <typename Tp>
inline Tp min(Tp a , Tp b) {
if (a < b) return a;
else return b;
}
template <typename Tp>
inline void swap(Tp &a , Tp &b) {
Tp t = a;
a = b;
b = t;
}
template <typename Tp>
inline Tp abs(Tp &a) {
if (a < 0) return -a;
else return a;
}
inline void sp() {
putchar(32);
}
inline void et() {
putchar(10);
}
}
using namespace STman;
struct Edge {
int v, nx;
}e[MAXN * 100];
int n, m, dfn[MAXN], low[MAXN], num, tim, st[MAXN], top, in[MAXN], si[MAXN], kk;
int x[MAXN], y[MAXN], cnt, tot[MAXN], vis[MAXN], p[MAXN], ans, ecnt, head[MAXN];
void add(int f, int t) {
e[++ecnt] = (Edge) {t, head[f]};
head[f] = ecnt;
}
void tarjan(int u) {
dfn[u] = low[u] = ++tim;
st[++top] = u;
vis[u] = 1;
for (int i = head[u]; i; i = e[i].nx) {
int v = e[i].v;
if (!dfn[v]) {
tarjan(v);
low[u] = min(low[u], low[v]);
}
else if (vis[v]) low[u] = min(low[u], dfn[v]);
}
if (low[u] == dfn[u]) {
num++;
int v;
do {
v = st[top--];
vis[v] = 0;
in[v] = num;
si[v]++;
} while (u != v);
}
}
void dfs(int u, int t) {
tot[u] += p[u], vis[u] = t;
for (int i = head[u]; i; i = e[i].nx) {
int to = e[i].v;
if (vis[to] == t) continue;
dfs(to, t);
}
}
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
int c;
scanf("%1d", &c);
if (c == 1) {
x[++cnt] = i, y[cnt] = j;
add(i, j);
}
}
}
for (int i = 1; i <= n; i++) {
if (!dfn[i]) tarjan(i);
}
memset(head, 0, sizeof(head));
memset(e, 0, sizeof(e));
memset(vis, 0, sizeof(vis));
ecnt = 0;
for (int i = 1; i <= cnt; i++) {
if (in[x[i]] != in[y[i]]) {
add(in[x[i]], in[y[i]]);
}
}
for (int i = 1; i <= n; i++) {
p[in[i]]++;
}
for (int i = 1; i <= n; i++) {
dfs(in[i], ++kk);
}
for (int i = 1; i <= num; i++) {
ans += tot[i];
}
write(ans), et();
}
文章作者: RiverFun
文章链接: https://stevebraveman.github.io/blog/2018/12/11/49/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 RiverFun

评论