OR-Tools  8.0
connected_components.cc
Go to the documentation of this file.
1 // Copyright 2010-2018 Google LLC
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 
14 //
15 // Licensed under the Apache License, Version 2.0 (the "License");
16 // you may not use this file except in compliance with the License.
17 // You may obtain a copy of the License at
18 //
19 // http://www.apache.org/licenses/LICENSE-2.0
20 //
21 // Unless required by applicable law or agreed to in writing, software
22 // distributed under the License is distributed on an "AS IS" BASIS,
23 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
24 // See the License for the specific language governing permissions and
25 // limitations under the License.
26 
27 // The following uses disjoint-sets algorithms, see:
28 // https://en.wikipedia.org/wiki/Disjoint-set_data_structure#Disjoint-set_forests
29 
31 
32 #include <numeric>
33 
35  const int old_num_nodes = GetNumberOfNodes();
36  if (num_nodes == old_num_nodes) {
37  return;
38  }
39  CHECK_GT(num_nodes, old_num_nodes);
40  // Each new node starts as an isolated component:
41  // It has itself as root.
42  parent_.resize(num_nodes);
43  std::iota(parent_.begin() + old_num_nodes, parent_.end(), old_num_nodes);
44  // It's in an isolated component of size 1.
45  component_size_.resize(num_nodes, 1);
46  // Its rank is 0.
47  rank_.resize(num_nodes);
48  // This introduces one extra component per added node.
49  num_components_ += num_nodes - old_num_nodes;
50 }
51 
53  DCHECK_GE(node, 0);
54  DCHECK_LT(node, GetNumberOfNodes());
55 
56  // Search the root.
57  int root = parent_[node];
58  while (parent_[root] != root) {
59  root = parent_[root];
60  }
61 
62  // Apply path compression.
63  while (node != root) {
64  const int prev_parent = parent_[node];
65  parent_[node] = root;
66  node = prev_parent;
67  }
68  return root;
69 }
70 
71 void DenseConnectedComponentsFinder::AddEdge(int node1, int node2) {
72  // Grow if needed.
73  const int min_num_nodes = std::max(node1, node2) + 1;
74  if (min_num_nodes > GetNumberOfNodes()) {
75  SetNumberOfNodes(min_num_nodes);
76  }
77 
78  // Just union the sets for node1 and node2.
79  int root1 = FindRoot(node1);
80  int root2 = FindRoot(node2);
81 
82  // Already the same set.
83  if (root1 == root2) {
84  return;
85  }
86 
87  DCHECK_GE(num_components_, 2);
88  --num_components_;
89 
90  const int component_size = component_size_[root1] + component_size_[root2];
91 
92  // Attach the shallowest tree to root of the deepest one. Note that this
93  // operation grows the rank of the new common root by at most one (if the two
94  // trees originally have the same rank).
95  if (rank_[root1] > rank_[root2]) {
96  parent_[root2] = root1;
97  component_size_[root1] = component_size;
98  } else {
99  parent_[root1] = root2;
100  component_size_[root2] = component_size;
101  // If the ranks were the same then attaching just grew the rank by one.
102  if (rank_[root1] == rank_[root2]) {
103  ++rank_[root2];
104  }
105  }
106 }
107 
108 bool DenseConnectedComponentsFinder::Connected(int node1, int node2) {
109  if (node1 < 0 || node1 >= GetNumberOfNodes() || node2 < 0 ||
110  node2 >= GetNumberOfNodes()) {
111  return false;
112  }
113  return FindRoot(node1) == FindRoot(node2);
114 }
115 
117  if (node < 0 || node >= GetNumberOfNodes()) {
118  return 0;
119  }
120  return component_size_[FindRoot(node)];
121 }
122 
124  std::vector<int> component_ids(GetNumberOfNodes(), -1);
125  int current_component = 0;
126  for (int node = 0; node < GetNumberOfNodes(); ++node) {
127  int& root_component = component_ids[FindRoot(node)];
128  if (root_component < 0) {
129  // This is the first node in a yet unseen component.
130  root_component = current_component;
131  ++current_component;
132  }
133  component_ids[node] = root_component;
134  }
135  return component_ids;
136 }
max
int64 max
Definition: alldiff_cst.cc:139
DenseConnectedComponentsFinder::GetSize
int GetSize(int node)
Definition: connected_components.cc:116
DenseConnectedComponentsFinder::AddEdge
void AddEdge(int node1, int node2)
Definition: connected_components.cc:71
DenseConnectedComponentsFinder::FindRoot
int FindRoot(int node)
Definition: connected_components.cc:52
connected_components.h
DenseConnectedComponentsFinder::GetNumberOfNodes
int GetNumberOfNodes() const
Definition: connected_components.h:96
DenseConnectedComponentsFinder::SetNumberOfNodes
void SetNumberOfNodes(int num_nodes)
Definition: connected_components.cc:34
DenseConnectedComponentsFinder::Connected
bool Connected(int node1, int node2)
Definition: connected_components.cc:108
DenseConnectedComponentsFinder::GetComponentIds
std::vector< int > GetComponentIds()
Definition: connected_components.cc:123