22 #include "absl/container/flat_hash_set.h"
28 inline bool Connects(std::function<
bool(
int,
int)> graph,
int i,
int j) {
29 return i == j || graph(i, j);
52 void Search(std::function<
bool(
int,
int)> graph,
53 std::function<
bool(
const std::vector<int>&)>
callback,
54 int* input_candidates,
int first_candidate_index,
55 int num_input_candidates, std::vector<int>* current_clique,
67 int disconnected_node = 0;
75 int num_disconnected_candidates = num_input_candidates;
80 int pre_increment = 0;
83 for (
int i = 0; i < num_input_candidates && num_disconnected_candidates != 0;
85 int pivot_candidate = input_candidates[i];
95 int disconnected_node_candidate = 0;
100 for (
int j = first_candidate_index;
101 j < num_input_candidates && count < num_disconnected_candidates; ++j) {
102 if (!Connects(graph, pivot_candidate, input_candidates[j])) {
104 disconnected_node_candidate = j;
110 if (count < num_disconnected_candidates) {
111 pivot = pivot_candidate;
112 num_disconnected_candidates = count;
114 if (i < first_candidate_index) {
115 disconnected_node = disconnected_node_candidate;
117 disconnected_node = i;
125 std::vector<int> new_candidates;
126 new_candidates.reserve(num_input_candidates);
127 for (
int remaining_candidates = num_disconnected_candidates + pre_increment;
128 remaining_candidates >= 1; remaining_candidates--) {
132 const int selected = input_candidates[disconnected_node];
133 std::swap(input_candidates[disconnected_node],
134 input_candidates[first_candidate_index]);
137 new_candidates.clear();
138 for (
int i = 0; i < first_candidate_index; ++i) {
139 if (Connects(graph, selected, input_candidates[i])) {
140 new_candidates.push_back(input_candidates[i]);
143 const int new_first_candidate_index = new_candidates.size();
144 for (
int i = first_candidate_index + 1; i < num_input_candidates; ++i) {
145 if (Connects(graph, selected, input_candidates[i])) {
146 new_candidates.push_back(input_candidates[i]);
149 const int new_candidate_size = new_candidates.size();
152 current_clique->push_back(selected);
156 if (new_candidate_size == 0) {
159 if (new_first_candidate_index < new_candidate_size) {
160 Search(graph,
callback, new_candidates.data(),
161 new_first_candidate_index, new_candidate_size, current_clique,
170 current_clique->pop_back();
175 first_candidate_index++;
178 if (remaining_candidates > 1) {
179 disconnected_node = first_candidate_index;
180 while (disconnected_node < num_input_candidates &&
181 Connects(graph, pivot, input_candidates[disconnected_node])) {
188 class FindAndEliminate {
190 FindAndEliminate(std::function<
bool(
int,
int)> graph,
int node_count,
191 std::function<
bool(
const std::vector<int>&)>
callback)
192 : graph_(graph), node_count_(node_count), callback_(
callback) {}
194 bool GraphCallback(
int node1,
int node2) {
200 return Connects(graph_, node1, node2);
203 bool SolutionCallback(
const std::vector<int>& solution) {
204 const int size = solution.size();
206 for (
int i = 0; i < size - 1; ++i) {
207 for (
int j = i + 1; j < size; ++j) {
208 visited_.insert(std::make_pair(
std::min(solution[i], solution[j]),
209 std::max(solution[i], solution[j])));
218 std::function<bool(
int,
int)> graph_;
220 std::function<bool(
const std::vector<int>&)> callback_;
221 absl::flat_hash_set<std::pair<int, int>> visited_;
227 void FindCliques(std::function<
bool(
int,
int)> graph,
int node_count,
228 std::function<
bool(
const std::vector<int>&)>
callback) {
229 std::unique_ptr<int[]> initial_candidates(
new int[node_count]);
230 std::vector<int> actual;
232 for (
int c = 0; c < node_count; ++c) {
233 initial_candidates[c] = c;
237 Search(graph,
callback, initial_candidates.get(), 0, node_count, &actual,
242 std::function<
bool(
const std::vector<int>&)>
callback) {
243 FindAndEliminate cache(graph, node_count,
callback);
244 std::unique_ptr<int[]> initial_candidates(
new int[node_count]);
245 std::vector<int> actual;
247 std::function<bool(
int,
int)> cached_graph = [&cache](
int i,
int j) {
248 return cache.GraphCallback(i, j);
250 std::function<bool(
const std::vector<int>&)> cached_callback =
251 [&cache](
const std::vector<int>& res) {
252 return cache.SolutionCallback(res);
255 for (
int c = 0; c < node_count; ++c) {
256 initial_candidates[c] = c;
260 Search(cached_graph, cached_callback, initial_candidates.get(), 0, node_count,
void swap(IdMap< K, V > &a, IdMap< K, V > &b)
Collection of objects used to extend the Constraint Solver library.
void CoverArcsByCliques(std::function< bool(int, int)> graph, int node_count, std::function< bool(const std::vector< int > &)> callback)
void FindCliques(std::function< bool(int, int)> graph, int node_count, std::function< bool(const std::vector< int > &)> callback)