Raw File
opt.cpp
#include "opt.hpp"

volatile sig_atomic_t tle = false;

void signalHandler(int) { tle = true; }

inline void initPriorityQueue(const Tree &T, const Vertex root,
                              const vector<map<Vertex, Weight>> &adjList,
                              vector<Weight> &min_distance,
                              vector<Vertex> &origin,
                              set<pair<Weight, Vertex>> &active_vertices) {
  queue<Vertex> next;
  next.push(root);
  while (!next.empty()) {
    Vertex current = next.front();
    next.pop();

    for (map<Vertex, Weight>::const_iterator it = adjList[current].begin();
         it != adjList[current].end(); ++it) {
      set<Vertex>::const_iterator son =
          T.tree[current].children.find(it->first);
      if (son != T.tree[current].children.end()) {
        next.push(*son);
        active_vertices.erase({min_distance[it->first], it->first});
        min_distance[it->first] = 0;
        origin[it->first] = current;
      } else if (min_distance[it->first] > it->second) {
        active_vertices.erase({min_distance[it->first], it->first});
        active_vertices.insert({it->second, it->first});
        min_distance[it->first] = it->second;
        origin[it->first] = current;
      }
    }
  }
}

inline Vertex deleteUpPath(Vertex v, const vector<int> &terminalsMap, Tree &T) {
  while (T.tree[v].children.empty() && terminalsMap[v] == -1 &&
         T.tree[v].parent >= 0) {
    Vertex parent = T.tree[v].parent;
    T.tree[parent].children.erase(v);
    T.tree[v].parent = -2;
    v = parent;
  }
  return v;
}

inline void buildDownPath(const vector<map<Vertex, Weight>> &adjList,
                          const vector<Weight> &min_distance,
                          const vector<Vertex> &origin, Vertex cible, Tree &T) {
  while (origin[cible] != -1) {
    if (T.tree[origin[cible]].parent >= 0) {
      T.tree[T.tree[origin[cible]].parent].children.erase(origin[cible]);
    }
    T.tree[cible].children.insert(origin[cible]);
    T.tree[origin[cible]].parent = cible;
    if (T.tree[origin[cible]].parent == -2) {
      T.tree[origin[cible]].weight =
          min_distance[cible] - min_distance[origin[cible]];
    } else {
      T.tree[origin[cible]].weight = adjList[cible].find(origin[cible])->second;
    }
    cible = origin[cible];
  }
}

inline void buildUpPath(const vector<map<Vertex, Weight>> &adjList,
                        const vector<Weight> &min_distance,
                        const vector<Vertex> &origin, Vertex current, Tree &T) {
  while (origin[current] != -1) {
    if (T.tree[current].parent == origin[current]) {
      current = origin[current];
    } else {
      if (T.tree[current].parent >= 0)
        T.tree[T.tree[current].parent].children.erase(current);
      T.tree[origin[current]].children.insert(current);
      T.tree[current].parent = origin[current];
      if (T.tree[current].parent >= 0) {
        T.tree[current].weight =
            min_distance[current] - min_distance[origin[current]];
      } else {
        T.tree[current].weight = adjList[current].find(origin[current])->second;
      }
      current = origin[current];
    }
  }
}

inline void opt_d3(Vertex root, Vertex v1, Vertex v2,
                   const vector<map<Vertex, Weight>> &adjList,
                   vector<Vertex> terminalsMap, Tree &T) {

  if (T.tree[v1].parent >= 0) {
    T.tree[T.tree[v1].parent].children.erase(v1);
    deleteUpPath(T.tree[v1].parent, terminalsMap, T);
  }
  if (T.tree[v2].parent >= 0) {
    T.tree[T.tree[v2].parent].children.erase(v2);
    deleteUpPath(T.tree[v2].parent, terminalsMap, T);
  }

  while (T.tree[v1].children.size() == 1 && terminalsMap[v1] == -1) {
    T.tree[v1].parent = -2;
    Vertex tmp = v1;
    v1 = *T.tree[v1].children.begin();
    T.tree[tmp].children.clear();
  }
  T.tree[v1].parent = -1;

  while (T.tree[v2].children.size() == 1 && terminalsMap[v2] == -1) {
    T.tree[v2].parent = -2;
    Vertex tmp = v2;
    v2 = *T.tree[v2].children.begin();
    T.tree[tmp].children.clear();
  }
  T.tree[v2].parent = -1;

  // Dijkstra from v1
  set<pair<Weight, Vertex>> active_vertices;
  vector<Weight> min_distance1(adjList.size(), MAX_WEIGHT);
  vector<Vertex> origin1(adjList.size(), -1);
  min_distance1[v1] = 0;

  initPriorityQueue(T, v1, adjList, min_distance1, origin1, active_vertices);
  Vertex c1 = dijkstra(adjList, min_distance1, origin1, T, active_vertices);

  // Dijkstra from v2
  active_vertices.clear();
  vector<Weight> min_distance2(adjList.size(), MAX_WEIGHT);
  vector<Vertex> origin2(adjList.size(), -1);
  min_distance2[v2] = 0;

  initPriorityQueue(T, v2, adjList, min_distance2, origin2, active_vertices);
  Vertex c2 = dijkstra(adjList, min_distance2, origin2, T, active_vertices);

  // Dijkstra from root
  active_vertices.clear();
  vector<Weight> min_distance0(adjList.size(), MAX_WEIGHT);
  vector<Vertex> origin0(adjList.size(), -1);
  min_distance0[root] = 0;

  initPriorityQueue(T, root, adjList, min_distance0, origin0, active_vertices);
  Vertex c0 = dijkstra(adjList, min_distance0, origin0, T, active_vertices);

  Vertex r1;
  if (min_distance2[c1] == 0) {
    r1 = v2;
  } else {
    r1 = root;
  }
  Vertex r2;
  if (min_distance1[c2] == 0) {
    r2 = v1;
  } else {
    r2 = root;
  }
  Vertex r0;
  if (min_distance1[c0] == 0) {
    r0 = v1;
  } else {
    r0 = v2;
  }

  Vertex intersect = -1;
  Weight distIntersect = MAX_WEIGHT;
  if (r1 == root || r2 == root) {
    distIntersect = min_distance1[c1] + min_distance2[c2];
  } else if (r0 == v1) {
    distIntersect = min_distance0[c0] + min_distance2[c2];
  } else {
    distIntersect = min_distance0[c0] + min_distance1[c1];
  }
  for (unsigned int i = 0; i < adjList.size(); ++i) {
    if (min_distance2[i] != MAX_WEIGHT && min_distance1[i] != MAX_WEIGHT &&
        min_distance0[i] != MAX_WEIGHT &&
        min_distance0[i] + min_distance1[i] + min_distance2[i] <
            distIntersect) {
      intersect = i;
      distIntersect = min_distance0[i] + min_distance1[i] + min_distance2[i];
    }
  }

  if (intersect != -1) {
    // Build the tree with origin1
    buildDownPath(adjList, min_distance1, origin1, intersect, T);

    // Build the tree with origin2
    buildDownPath(adjList, min_distance2, origin2, intersect, T);

    // Build the tree with origin0
    buildUpPath(adjList, min_distance0, origin0, intersect, T);
  } else {
    if (r2 == root) {
      // Build the tree with origin1
      buildDownPath(adjList, min_distance1, origin1, c1, T);
      // Build the tree with origin2
      buildDownPath(adjList, min_distance2, origin2, c2, T);
    } else if (r1 == root) {
      // Build the tree with origin2
      buildDownPath(adjList, min_distance2, origin2, c2, T);
      // Build the tree with origin1
      buildDownPath(adjList, min_distance1, origin1, c1, T);
    } else {
      // Build the tree with origin1
      if (r0 == v1) {
        // Build the tree with origin2
        buildDownPath(adjList, min_distance2, origin2, c2, T);
        // Build the tree with origin1
        buildDownPath(adjList, min_distance1, origin1, c0, T);
      } else {
        // Build the tree with origin1
        buildDownPath(adjList, min_distance1, origin1, c1, T);
        // Build the tree with origin2
        buildDownPath(adjList, min_distance2, origin2, c0, T);
      }

      // Build the tree with origin0
      buildUpPath(adjList, min_distance0, origin0, c0, T);
    }
  }
}

inline void opt_d3_parent(Vertex node, Tree &T,
                          const vector<map<Vertex, Weight>> &adjList,
                          const vector<int> &terminalsMap) {
  vector<Vertex> backup_children(T.tree[node].children.begin(),
                                 T.tree[node].children.end());
  for (vector<Vertex>::iterator it1 = backup_children.begin();
       it1 != backup_children.end(); ++it1) {
    if (T.tree[node].parent < 0 || tle)
      return;
    set<Vertex>::iterator tmp_it = T.tree[node].children.find(*it1);
    if (tmp_it == T.tree[node].children.end())
      return;
    Vertex v1 = *tmp_it;
    Vertex v2 = node;

    opt_d3(T.root, v1, v2, adjList, terminalsMap, T);
  }
}

inline void opt_d3_son(Vertex node, Tree &T,
                       const vector<map<Vertex, Weight>> &adjList,
                       const vector<int> &terminalsMap) {
  vector<Vertex> backup_children(T.tree[node].children.begin(),
                                 T.tree[node].children.end());
  for (vector<Vertex>::iterator it1 = backup_children.begin();
       it1 != backup_children.end(); ++it1) {
    if (T.tree[node].parent == -2)
      return;
    for (vector<Vertex>::iterator it2 = it1 + 1; it2 != backup_children.end();
         ++it2) {
      if (tle)
        return;
      if (T.tree[node].parent == -2)
        break;
      if (T.tree[node].children.find(*it1) == T.tree[node].children.end())
        break;
      if (T.tree[node].children.find(*it2) == T.tree[node].children.end())
        continue;

      opt_d3(T.root, *it1, *it2, adjList, terminalsMap, T);
    }
  }
}

void apply_opt(Tree &T, const Graph &G) {
  vector<Vertex> next_opt;
  next_opt.reserve(G.adjList.size());
  {
    queue<Vertex> next;
    next.push(T.root);

    // We start the optimisation by the leaves
    // Fill next_opt with the order
    while (!next.empty()) {
      Vertex current = next.front();
      next.pop();

      for (set<Vertex>::iterator it = T.tree[current].children.begin();
           it != T.tree[current].children.end(); ++it) {
        next.push(*it);
        if (tle)
          return;
      }
      next_opt.push_back(current);
    }
  }

  // Apply optimisation following the next_opt order
  for (vector<Vertex>::reverse_iterator it = next_opt.rbegin();
       it != next_opt.rend(); ++it) {
    if (T.tree[*it].parent > -2) {

      // Optimisation for node of degree 3 or more
      if (tle)
        return;
      if (T.tree[*it].children.size() > 1) {
        opt_d3_son(*it, T, G.adjList, G.terminalsMap);
      }
      if (tle)
        return;
      if (T.tree[*it].children.size() > 2 ||
          (T.tree[*it].children.size() == 2 && G.terminalsMap[*it] != -1)) {
        opt_d3_parent(*it, T, G.adjList, G.terminalsMap);
      }
    }
  }
}

void full_d3(Tree &T, const Graph &G) {
  vector<Vertex> next_opt;
  next_opt.reserve(G.adjList.size());
  {
    queue<Vertex> next;
    next.push(T.root);

    while (!next.empty()) {
      Vertex current = next.front();
      next.pop();

      for (set<Vertex>::iterator it = T.tree[current].children.begin();
           it != T.tree[current].children.end(); ++it) {
        if (T.tree[*it].children.size() > 1 || G.terminalsMap[*it])
          next_opt.push_back(*it);
        next.push(*it);
        if (tle)
          return;
      }
    }
  }

  for (vector<Vertex>::iterator it1 = next_opt.begin(); it1 != next_opt.end();
       ++it1) {
    for (vector<Vertex>::iterator it2 = it1 + 1; it2 != next_opt.end(); ++it2) {
      if (tle)
        return;
      if (T.tree[*it1].parent != -2) {
        if (T.tree[*it2].parent != -2) {
          if ((T.tree[*it1].children.size() > 1 ||
               G.terminalsMap[*it1] != -1) &&
              (T.tree[*it2].children.size() > 1 ||
               G.terminalsMap[*it2] != -1)) {
            opt_d3(T.root, *it1, *it2, G.adjList, G.terminalsMap, T);
          }
        }
      }
    }
  }
}
back to top