#include "init.hpp"
inline void steiner_3(const vector<map<Vertex, Weight>> &adjList,
vector<Weight> &min_distance0, vector<Vertex> &origin0,
Vertex v0, Vertex v1, Vertex v2) {
vector<Weight> min_distance1(adjList.size(), MAX_WEIGHT);
vector<Vertex> origin1(adjList.size(), -1);
vector<Weight> min_distance2(adjList.size(), MAX_WEIGHT);
vector<Vertex> origin2(adjList.size(), -1);
dijkstra(adjList, min_distance1, origin1, v1, v0, v2);
if (min_distance0[v2] == min_distance1[v2]) {
dijkstra(adjList, min_distance2, origin2, v2, v0, v1);
} else {
if (min_distance0[v2] < min_distance1[v2]) {
dijkstra(adjList, min_distance2, origin2, v2, v0);
} else {
dijkstra(adjList, min_distance2, origin2, v2, v1);
}
}
Vertex intersect = -1;
Weight distIntersect = MAX_WEIGHT;
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];
}
}
// Fill seen
vector<bool> seen(adjList.size(), false);
Vertex current = intersect;
while (origin0[current] != -1) {
seen[current] = true;
current = origin0[current];
}
seen[current] = true;
// Merge origin1 into origin0
current = intersect;
while (origin1[current] != -1) {
if (!seen[origin1[current]]) {
origin0[origin1[current]] = current;
}
seen[current] = true;
current = origin1[current];
}
seen[current] = true;
// Merge origin2 into origin0
current = intersect;
while (origin2[current] != -1) {
if (!seen[origin2[current]]) {
origin0[origin2[current]] = current;
}
current = origin2[current];
}
}
Tree incrementalDijks3(const Graph &G, Vertex root,
const vector<int> &terminalsMap,
const vector<Vertex> &terminals) {
vector<std::map<Vertex, Weight>> adjList = G.adjList;
vector<Weight> min_distance(G.adjList.size(), MAX_WEIGHT);
vector<Vertex> origin(G.adjList.size(), -1);
Vertex far = dijkstra(adjList, min_distance, origin, root, terminalsMap,
terminals.size());
Weight far_dist = min_distance[far];
Vertex last_far = far;
bool dijk_simple = true;
while (far_dist > 0 && !tle) {
if (dijk_simple) {
dijk_simple = false;
vector<Weight> copy_distance = min_distance;
vector<Vertex> copy_origin = origin;
// Update graph, set edge to 0
last_far = far;
Vertex current = far;
while (origin[current] != -1 && copy_distance[current] != 0) {
copy_distance[current] = 0;
current = origin[current];
}
current = far;
set<pair<Weight, Vertex>> active_vertices;
while (origin[current] != -1 && min_distance[current] != 0) {
for (map<Vertex, Weight>::const_iterator it = adjList[current].begin();
it != adjList[current].end(); ++it) {
if (it->first != copy_origin[current] &&
copy_distance[it->first] > it->second) {
active_vertices.erase({copy_distance[it->first], it->first});
active_vertices.insert({it->second, it->first});
copy_distance[it->first] = it->second;
copy_origin[it->first] = current;
}
}
current = origin[current];
}
dijkstra(adjList, copy_distance, copy_origin, active_vertices);
far_dist = 0;
for (vector<Vertex>::const_iterator it = terminals.begin();
it != terminals.end(); ++it) {
if (far_dist < copy_distance[*it]) {
far_dist = copy_distance[*it];
far = *it;
}
}
} else {
dijk_simple = true;
steiner_3(adjList, min_distance, origin, root, far, last_far);
// Update graph
Vertex current = far;
while (origin[current] != -1) {
adjList[current][origin[current]] = 0;
adjList[origin[current]][current] = 0;
min_distance[current] = MAX_WEIGHT;
current = origin[current];
}
current = last_far;
while (origin[current] != -1) {
adjList[current][origin[current]] = 0;
adjList[origin[current]][current] = 0;
min_distance[current] = MAX_WEIGHT;
current = origin[current];
}
dijkstra(adjList, min_distance, origin, root);
far_dist = 0;
for (vector<Vertex>::const_iterator it = terminals.begin();
it != terminals.end(); ++it) {
if (far_dist < min_distance[*it]) {
far_dist = min_distance[*it];
far = *it;
}
}
}
}
// Build tree
Tree T(G, root);
for (unsigned int i = 0; i < G.adjList.size(); ++i) {
if (origin[i] != -1) {
T.tree[i].parent = origin[i];
T.tree[i].weight = G.adjList[i].find(origin[i])->second;
T.tree[origin[i]].children.insert(i);
}
}
return T;
}
Tree incrementalOptDijks3(const Graph &G, Vertex root,
const vector<int> &terminalsMap,
const vector<Vertex> &terminals) {
vector<std::map<Vertex, Weight>> adjList = G.adjList;
vector<Weight> min_distance(G.adjList.size(), MAX_WEIGHT);
vector<Vertex> origin(G.adjList.size(), -1);
Vertex far = dijkstra(adjList, min_distance, origin, root, terminalsMap,
terminals.size());
Weight far_dist = min_distance[far];
vector<Weight> full_backup_distance = min_distance;
vector<Vertex> full_backup_origin = origin;
vector<Vertex> current_terminals;
vector<int> current_terminalsMap(terminalsMap.size(), -1);
current_terminals.reserve(terminals.size());
Vertex last_far = far;
while (far_dist > 0 && !tle) {
bool dijk_simple = true;
for (int i = 0; i < 4 && far_dist > 0 && !tle; ++i) {
if (dijk_simple) {
current_terminalsMap[far] = current_terminals.size();
current_terminals.push_back(far);
dijk_simple = false;
vector<Weight> backup_distance = min_distance;
vector<Vertex> backup_origin = origin;
// Update graph, set edge to 0
last_far = far;
Vertex current = far;
while (origin[current] != -1 && min_distance[current] != 0) {
backup_distance[current] = 0;
current = origin[current];
}
current = far;
set<pair<Weight, Vertex>> active_vertices;
while (origin[current] != -1 && min_distance[current] != 0) {
for (map<Vertex, Weight>::iterator it = adjList[current].begin();
it != adjList[current].end(); ++it) {
if (backup_distance[it->first] > it->second) {
active_vertices.erase({backup_distance[it->first], it->first});
active_vertices.insert({it->second, it->first});
backup_distance[it->first] = it->second;
backup_origin[it->first] = current;
}
}
current = origin[current];
}
dijkstra(adjList, backup_distance, backup_origin, active_vertices);
far_dist = 0;
for (vector<Vertex>::const_iterator it = terminals.begin();
it != terminals.end(); ++it) {
if (far_dist < backup_distance[*it]) {
far_dist = backup_distance[*it];
far = *it;
}
}
} else {
dijk_simple = true;
current_terminalsMap[far] = current_terminals.size();
current_terminals.push_back(far);
steiner_3(adjList, min_distance, origin, root, far, last_far);
// Update graph
Vertex current = far;
while (origin[current] != -1) {
adjList[current][origin[current]] = 0;
adjList[origin[current]][current] = 0;
min_distance[current] = MAX_WEIGHT;
current = origin[current];
}
current = last_far;
while (origin[current] != -1) {
adjList[current][origin[current]] = 0;
adjList[origin[current]][current] = 0;
min_distance[current] = MAX_WEIGHT;
current = origin[current];
}
dijkstra(adjList, min_distance, origin, root);
far_dist = 0;
for (vector<Vertex>::const_iterator it = terminals.begin();
it != terminals.end(); ++it) {
if (far_dist < min_distance[*it]) {
far_dist = min_distance[*it];
far = *it;
}
}
}
}
Tree T(G, root);
for (unsigned int i = 0; i < G.adjList.size(); ++i) {
if (origin[i] != -1) {
T.tree[i].parent = origin[i];
T.tree[i].weight = G.adjList[i].find(origin[i])->second;
T.tree[origin[i]].children.insert(i);
}
}
Weight oldw, w = T.pruneLeaves(G.terminalsMap);
do {
if (tle)
break;
oldw = w;
apply_opt(T, G);
w = T.pruneLeaves(G.terminalsMap);
} while (oldw != w);
if (tle)
break;
adjList = G.adjList;
origin = full_backup_origin;
min_distance = full_backup_distance;
stack<Vertex> next;
next.push(T.root);
while (!next.empty()) {
Vertex current = next.top();
next.pop();
for (set<Vertex>::iterator it = T.tree[current].children.begin();
it != T.tree[current].children.end(); ++it) {
next.push(*it);
min_distance[*it] = MAX_WEIGHT;
origin[*it] = -1;
adjList[current][*it] = 0;
adjList[*it][current] = 0;
}
}
if (tle)
break;
dijkstra(adjList, min_distance, origin, root);
far_dist = 0;
for (vector<Vertex>::const_iterator it = terminals.begin();
it != terminals.end(); ++it) {
if (far_dist < min_distance[*it]) {
far_dist = min_distance[*it];
far = *it;
}
}
}
// Build tree
Tree T(G, root);
for (unsigned int i = 0; i < G.adjList.size(); ++i) {
if (origin[i] != -1) {
T.tree[i].parent = origin[i];
T.tree[i].weight = G.adjList[i].find(origin[i])->second;
T.tree[origin[i]].children.insert(i);
}
}
return T;
}
bool cmp(const tuple<Weight, Vertex, Vertex> &x,
const tuple<Weight, Vertex, Vertex> &y) {
return get<0>(x) > get<0>(y);
}
Tree mst(const Graph &G, Vertex root) {
Tree T(G, root);
vector<tuple<Weight, Vertex, Vertex>> active_vertices;
for (pair<Vertex, Weight> neighbour : G.adjList[root]) {
active_vertices.push_back(
tuple<Weight, Vertex, Vertex>(neighbour.second, root, neighbour.first));
}
make_heap(active_vertices.begin(), active_vertices.end(), cmp);
while (!active_vertices.empty()) {
std::pop_heap(active_vertices.begin(), active_vertices.end(), cmp);
tuple<Weight, Vertex, Vertex> edge = active_vertices.back();
active_vertices.pop_back();
if (T.tree[get<2>(edge)].parent == -2) {
T.tree[get<2>(edge)].parent = get<1>(edge);
T.tree[get<2>(edge)].weight = get<0>(edge);
T.tree[get<1>(edge)].children.insert(get<2>(edge));
for (pair<Vertex, Weight> neighbour : G.adjList[get<2>(edge)]) {
if (T.tree[neighbour.first].parent == -2) {
active_vertices.push_back(tuple<Weight, Vertex, Vertex>(
neighbour.second, get<2>(edge), neighbour.first));
push_heap(active_vertices.begin(), active_vertices.end(), cmp);
}
}
}
}
return T;
}
Tree strong_bias_random(const Graph &G, Vertex root) {
Tree T(G, root);
default_random_engine generator;
vector<tuple<Weight, Vertex, Vertex>> active_vertices;
for (pair<Vertex, Weight> neighbour : G.adjList[root]) {
active_vertices.push_back(
tuple<Weight, Vertex, Vertex>(neighbour.second, root, neighbour.first));
}
while (!active_vertices.empty()) {
int position =
uniform_int_distribution<int>(0, active_vertices.size() - 1)(generator);
tuple<Weight, Vertex, Vertex> edge = active_vertices[position];
active_vertices[position] = active_vertices.back();
active_vertices.pop_back();
if (T.tree[get<2>(edge)].parent == -2) {
T.tree[get<2>(edge)].parent = get<1>(edge);
T.tree[get<2>(edge)].weight = get<0>(edge);
T.tree[get<1>(edge)].children.insert(get<2>(edge));
for (pair<Vertex, Weight> neighbour : G.adjList[get<2>(edge)]) {
if (T.tree[neighbour.first].parent == -2) {
active_vertices.push_back(tuple<Weight, Vertex, Vertex>(
neighbour.second, get<2>(edge), neighbour.first));
push_heap(active_vertices.begin(), active_vertices.end(), cmp);
}
}
}
}
return T;
}
Tree random(const Graph &G, Vertex root) {
vector<Vertex> origin(G.adjList.size(), -2);
origin[root] = -1;
default_random_engine generator;
for (Vertex t : G.terminals) {
vector<bool> seen(G.adjList.size(), false);
Vertex current = t;
while (origin[current] == -2 || seen[current]) {
seen[current] = true;
int position = uniform_int_distribution<int>(
0, G.adjList[current].size() - 1)(generator);
map<Vertex, Weight>::const_iterator it = G.adjList[current].begin();
advance(it, position);
Vertex next = it->first;
origin[current] = next;
current = next;
}
}
Tree T(G, root);
for (unsigned int i = 0; i < G.adjList.size(); ++i) {
if (origin[i] > -1) {
T.tree[i].parent = origin[i];
T.tree[i].weight = G.adjList[i].find(origin[i])->second;
T.tree[origin[i]].children.insert(i);
}
}
return T;
}