-
Notifications
You must be signed in to change notification settings - Fork 2
/
Extra edges to make directed graph fully connected.cpp
134 lines (111 loc) · 2.59 KB
/
Extra edges to make directed graph fully connected.cpp
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
134
/*8<
@Title:
Extra Edges to Make Digraph Fully Strongly
Connected
@Description:
Given a directed graph $G$ find the necessary
edges to add to make the graph a single
strongly connected component.
@Time:
$O(N+M)$
@Memory:
$O(N)$
>8*/
struct SCC {
int n, num_sccs;
vi2d adj;
vi scc_id;
SCC(int _n)
: n(_n),
num_sccs(0),
adj(n),
scc_id(n, -1) {}
SCC(const vi2d &_adj) : SCC(len(_adj)) {
adj = _adj;
find_sccs();
}
void add_edge(int u, int v) { adj[u].eb(v); }
void find_sccs() {
int timer = 1;
vi tin(n), st;
st.reserve(n);
function<int(int)> dfs = [&](int u) -> int {
int low = tin[u] = timer++, siz = len(st);
st.eb(u);
for (int v : adj[u])
if (scc_id[v] < 0)
low =
min(low, tin[v] ? tin[v] : dfs(v));
if (tin[u] == low) {
rep(i, siz, len(st)) scc_id[st[i]] =
num_sccs;
st.resize(siz);
num_sccs++;
}
return low;
};
for (int i = 0; i < n; i++)
if (!tin[i]) dfs(i);
}
};
vector<array<int, 2>> extra_edges(
const vi2d &adj) {
SCC scc(adj);
auto scc_id = scc.scc_id;
auto num_sccs = scc.num_sccs;
if (num_sccs == 1) return {};
int n = len(adj);
vi2d scc_adj(num_sccs);
vi zero_in(num_sccs, 1);
rep(u, 0, n) {
for (int v : adj[u]) {
if (scc_id[u] == scc_id[v]) continue;
scc_adj[scc_id[u]].eb(scc_id[v]);
zero_in[scc_id[v]] = 0;
}
}
int random_source =
max_element(all(zero_in)) - zero_in.begin();
vi vis(num_sccs);
function<int(int)> dfs = [&](int u) {
if (empty(scc_adj[u])) return u;
for (int v : scc_adj[u])
if (!vis[v]) {
vis[v] = 1;
int zero_out = dfs(v);
if (zero_out != -1) return zero_out;
}
return (int)-1;
};
vector<array<int, 2>> edges;
vi in_unused;
rep(i, 0, num_sccs) {
if (zero_in[i]) {
vis[i] = 1;
int zero_out = dfs(i);
if (zero_out != -1)
edges.push_back({zero_out, i});
else
in_unused.push_back(i);
}
}
rep(i, 1, len(edges)) {
swap(edges[i][0], edges[i - 1][0]);
}
rep(i, 0, num_sccs) {
if (scc_adj[i].empty() && !vis[i]) {
if (!in_unused.empty()) {
edges.push_back({i, in_unused.back()});
in_unused.pop_back();
} else {
edges.push_back({i, random_source});
}
}
}
for (int u : in_unused) edges.push_back({0, u});
vi to_node(num_sccs);
rep(i, 0, n) to_node[scc_id[i]] = i;
for (auto &[u, v] : edges)
u = to_node[u], v = to_node[v];
return edges;
}