21 #include "absl/container/flat_hash_set.h"
27 inline bool Connects(std::function<
bool(
int,
int)> graph,
int i,
int j) {
28 return i == j || graph(i, j);
51 void Search(std::function<
bool(
int,
int)> graph,
52 std::function<
bool(
const std::vector<int>&)>
callback,
53 int* input_candidates,
int first_candidate_index,
54 int num_input_candidates, std::vector<int>* current_clique,
66 int disconnected_node = 0;
74 int num_disconnected_candidates = num_input_candidates;
79 int pre_increment = 0;
82 for (
int i = 0; i < num_input_candidates && num_disconnected_candidates != 0;
84 int pivot_candidate = input_candidates[i];
94 int disconnected_node_candidate = 0;
99 for (
int j = first_candidate_index;
100 j < num_input_candidates && count < num_disconnected_candidates; ++j) {
101 if (!Connects(graph, pivot_candidate, input_candidates[j])) {
103 disconnected_node_candidate = j;
109 if (count < num_disconnected_candidates) {
110 pivot = pivot_candidate;
111 num_disconnected_candidates = count;
113 if (i < first_candidate_index) {
114 disconnected_node = disconnected_node_candidate;
116 disconnected_node = i;
124 std::vector<int> new_candidates;
125 new_candidates.reserve(num_input_candidates);
126 for (
int remaining_candidates = num_disconnected_candidates + pre_increment;
127 remaining_candidates >= 1; remaining_candidates--) {
131 const int selected = input_candidates[disconnected_node];
132 std::swap(input_candidates[disconnected_node],
133 input_candidates[first_candidate_index]);
136 new_candidates.clear();
137 for (
int i = 0; i < first_candidate_index; ++i) {
138 if (Connects(graph, selected, input_candidates[i])) {
139 new_candidates.push_back(input_candidates[i]);
142 const int new_first_candidate_index = new_candidates.size();
143 for (
int i = first_candidate_index + 1; i < num_input_candidates; ++i) {
144 if (Connects(graph, selected, input_candidates[i])) {
145 new_candidates.push_back(input_candidates[i]);
148 const int new_candidate_size = new_candidates.size();
151 current_clique->push_back(selected);
155 if (new_candidate_size == 0) {
158 if (new_first_candidate_index < new_candidate_size) {
159 Search(graph,
callback, new_candidates.data(),
160 new_first_candidate_index, new_candidate_size, current_clique,
169 current_clique->pop_back();
174 first_candidate_index++;
177 if (remaining_candidates > 1) {
178 disconnected_node = first_candidate_index;
179 while (disconnected_node < num_input_candidates &&
180 Connects(graph, pivot, input_candidates[disconnected_node])) {
187 class FindAndEliminate {
189 FindAndEliminate(std::function<
bool(
int,
int)> graph,
int node_count,
190 std::function<
bool(
const std::vector<int>&)>
callback)
191 : graph_(graph), node_count_(node_count), callback_(
callback) {}
193 bool GraphCallback(
int node1,
int node2) {
199 return Connects(graph_, node1, node2);
202 bool SolutionCallback(
const std::vector<int>& solution) {
203 const int size = solution.size();
205 for (
int i = 0; i < size - 1; ++i) {
206 for (
int j = i + 1; j < size; ++j) {
207 visited_.insert(std::make_pair(
std::min(solution[i], solution[j]),
208 std::max(solution[i], solution[j])));
217 std::function<bool(
int,
int)> graph_;
219 std::function<bool(
const std::vector<int>&)> callback_;
220 absl::flat_hash_set<std::pair<int, int>> visited_;
226 void FindCliques(std::function<
bool(
int,
int)> graph,
int node_count,
227 std::function<
bool(
const std::vector<int>&)>
callback) {
228 std::unique_ptr<int[]> initial_candidates(
new int[node_count]);
229 std::vector<int> actual;
231 for (
int c = 0; c < node_count; ++c) {
232 initial_candidates[c] = c;
236 Search(graph,
callback, initial_candidates.get(), 0, node_count, &actual,
241 std::function<
bool(
const std::vector<int>&)>
callback) {
242 FindAndEliminate cache(graph, node_count,
callback);
243 std::unique_ptr<int[]> initial_candidates(
new int[node_count]);
244 std::vector<int> actual;
246 std::function<bool(
int,
int)> cached_graph = [&cache](
int i,
int j) {
247 return cache.GraphCallback(i, j);
249 std::function<bool(
const std::vector<int>&)> cached_callback =
250 [&cache](
const std::vector<int>& res) {
251 return cache.SolutionCallback(res);
254 for (
int c = 0; c < node_count; ++c) {
255 initial_candidates[c] = c;
259 Search(cached_graph, cached_callback, initial_candidates.get(), 0, node_count,