Add BFS trace, index marks for vertices, and construct the cycle

This commit is contained in:
Thien Hoang 2019-06-03 11:16:56 +07:00
parent ce77577040
commit 99cb89e63f
1 changed files with 89 additions and 7 deletions

View File

@ -15,14 +15,62 @@ public:
using Dart_const_handle = typename Gmap::Dart_const_handle; using Dart_const_handle = typename Gmap::Dart_const_handle;
using Dart_container = std::vector<Dart_const_handle>; using Dart_container = std::vector<Dart_const_handle>;
using Path = CGAL::Path_on_surface<Gmap>; using Path = CGAL::Path_on_surface<Gmap>;
using Distance_type = int;
Shortest_noncontractible_cycle(Gmap& gmap) : Shortest_noncontractible_cycle(Gmap& gmap) :
m_gmap(gmap) { } m_gmap(gmap) { }
Path find_cycle(Dart_const_handle root) { Path find_cycle(Dart_const_handle root) {
Dart_container spanning_tree, noncon_edges; Dart_container spanning_tree, noncon_edges;
BFS(root, spanning_tree); std::vector<Distance_type> distance_from_root;
std::vector<size_type> index_marks;
std::vector<int> trace_index;
BFS(root, spanning_tree, distance_from_root, trace_index);
find_noncon_edges(spanning_tree, noncon_edges); find_noncon_edges(spanning_tree, noncon_edges);
mark_vertices_with_indicies(spanning_tree, index_marks);
Distance_type min_distance = -1;
Dart_const_handle min_noncon_edge;
int min_a = -1, min_b = -1;
for (auto dh : noncon_edges) {
Dart_const_handle a = dh, b = m_gmap.alpha<0>(a);
int index_a = 0, index_b = 0;
for (int i = 0; i < index_marks.size(); ++i) {
if (m_gmap.is_marked(a, index_marks[i])) index_a ^= (1 << i);
if (m_gmap.is_marked(b, index_marks[i])) index_b ^= (1 << i);
}
Distance_type sum_distance = distance_from_root[index_a] + distance_from_root[index_b];
if (min_distance < 0 || min_distance > sum_distance) {
min_distance = sum_distance;
min_noncon_edge = dh;
min_a = index_a;
min_b = index_b;
}
}
Path cycle(m_gmap);
if (min_distance < 0) return cycle; // empty cycle;
// Trace back the path from `a` to root
int ind;
do {
ind = min_a;
cycle.push_back(m_gmap.alpha<0>(spanning_tree[ind]));
ind = trace_index[ind];
} while (ind != -1);
// Reverse: now it is the path from root to `a`
cycle.reverse();
cycle.push_back(min_noncon_edge);
// Trace back the path from `b` to root
do {
ind = min_b;
cycle.push_back(m_gmap.alpha<0>(spanning_tree[ind]));
ind = trace_index[ind];
} while (ind != -1);
CGAL_assertion(cycle.is_closed());
return cycle;
} }
private: private:
@ -39,7 +87,8 @@ private:
/// Create a spanning tree using BFS /// Create a spanning tree using BFS
void BFS(Dart_const_handle root, Dart_container& spanning_tree) { void BFS(Dart_const_handle root, Dart_container& spanning_tree,
std::vector<int>& distance_from_root, std::vector<int>& trace_index) {
size_type vertex_visited; size_type vertex_visited;
try { try {
vertex_visited = m_gmap.get_new_mark(); vertex_visited = m_gmap.get_new_mark();
@ -47,12 +96,18 @@ private:
std::cerr << "No more free mark, exit." << std::endl; std::cerr << "No more free mark, exit." << std::endl;
exit(-1); exit(-1);
} }
std::queue<Dart_const_handle> q; // The first of pair is a dart of a 0-cell,
q.push(root); // the second of pair is the index of the dart leading to this 0-cell in spanning_tree
std::queue<std::pair<Dart_const_handle, int> > q;
// spanning_tree is empty (so far), so the index is -1
q.push(std::make_pair(root, -1));
mark_cell<0>(root, vertex_visited); mark_cell<0>(root, vertex_visited);
spanning_tree.push_back(root); distance_from_root.push_back(0);
// Note: distance_from_root will have n (= #0-cells) elements while spanning_tree only has n-1
while (q.size()) { while (q.size()) {
Dart_const_handle u = q.front(); Dart_const_handle u = q.front().first;
int ind = q.front().second;
q.pop(); q.pop();
for (auto it = m_gmap.template one_dart_per_incident_cell<1,0>(u).begin(), for (auto it = m_gmap.template one_dart_per_incident_cell<1,0>(u).begin(),
itend = m_gmap.template one_dart_per_incident_cell<1,0>(u).end(); itend = m_gmap.template one_dart_per_incident_cell<1,0>(u).end();
@ -60,8 +115,15 @@ private:
Dart_const_handle v = m_gmap.alpha<0>(it); Dart_const_handle v = m_gmap.alpha<0>(it);
if (!m_gmap.is_marked(v, vertex_visited)) { if (!m_gmap.is_marked(v, vertex_visited)) {
mark_cell<0>(v, vertex_visited); mark_cell<0>(v, vertex_visited);
q.push(v); if (ind == -1)
distance_from_root.push_back(1);
else
distance_from_root.push_back(1 + distance_from_root[ind+1]);
spanning_tree.push_back(it); spanning_tree.push_back(it);
// `it` will lead to v
q.push(make_pair(v, spanning_tree.size() - 1));
trace_index.push_back(ind);
// v will later be marked with the binary code of spanning_tree.size()
} }
} }
} }
@ -127,6 +189,26 @@ private:
m_gmap.free_mark(face_deleted); m_gmap.free_mark(face_deleted);
} }
void mark_vertices_with_indicies(const Dart_container& spanning_tree, std::vector<size_type>& index_marks) {
int n = spanning_tree.size()+1, bit_count = 0;
while (n) ++bit_count, n >> 1;
index_marks.resize(bit_count);
try {
for (int i = 0; i < index_marks.size(); ++i)
index_marks[i] = m_gmap.get_new_mark();
} catch (typename Gmap::Exception_no_more_available_mark) {
std::cerr << "No more free mark, exit." << std::endl;
exit(-1);
}
n = 0;
for (auto dh : spanning_tree) {
++n;
Dart_const_handle v = m_gmap.alpha<0>(dh);
for (int i = 0; i < index_marks.size(); ++i)
if (n & (1 << i)) mark_cell<0>(v, index_marks[i]);
}
}
Gmap m_gmap; Gmap m_gmap;
}; };