
Коды основных функций / [Код основных функций] Лаб. 4
.pdf
[Код основных функций] Лабораторная работа №4. Минимальный остов
//Get the current time.
//This function should be used only for measuring time
//(first call, algorithm, second call; then the difference between the values) double getProcTime() {
#if defined(_WIN32) // If Windows:
FILETIME createTime, exitTime, kernelTime, userTime;
if (GetProcessTimes(GetCurrentProcess(), &createTime, &exitTime, &kernelTime, &userTime) != -1)
return (ULARGE_INTEGER { {userTime.dwLowDateTime, userTime.dwHighDateTime } }).QuadPart / 10000000.L;
return 0;
#else // If Linux or MacOS:
return double(clock()) / CLOCKS_PER_SEC; #endif
}
/* Input:
vector<Edge<float>> edges1 {
{0, 2, 9}, {0, 3, 2}, {2, 6, 2}, {3, 6, 9}, {6, 8, 9}, {1, 4, 9}, {1, 5, 3}, {4, 7, 3}, {5, 7, 9}, {7, 8, 1}
}, edges2 {
{0, 1, 0.000000}, { 0, 2, 0.000000 }, { 0, 3, 0.000000 }, { 0, 21, 0.000000 },
{0, 22, 0.000000 },
{0, 23, 0.000000 }, { 1, 2, 5.000000 }, { 1, 3, 4.000000 }, { 1, 4, 5.000000 },
{1, 20, 1.000000 },
{1, 21, 4.000000 }, { 1, 22, 1.000000 }, { 2, 3, 12.000000 }, { 2, 4, 14.000000 }, { 2, 5, 8.000000 },
{2, 19, 10.000000 }, { 2, 20, 12.000000 }, { 2, 21, 8.000000 }
}, edges3 {
{0, 23, 0.000000 }, { 0, 22, 0.000000 }, { 0, 21, 0.000000 }, { 0, 2, 0.000000 },
{0, 3, 0.000000 },
{2, 4, 14.000000 }, { 2, 20, 12.000000 }, { 2, 19, 10.000000 }, { 2, 5, 8.000000
},
{0, 1, 0.000000}, { 1, 2, 5.000000 }, { 1, 3, 4.000000 }, { 1, 4, 5.000000 }, { 1, 20, 1.000000 },
{1, 21, 4.000000 }, { 1, 22, 1.000000 }, { 2, 3, 12.000000 }, { 2, 21,
8.000000 }
}, edges4 {
{ 0, 1, 1 }, { 0, 2, 1 }, {1, 2, 1}
};
Output: Verticles: 9
Prim's algorithm: {1 4 9} {0 2 9} {0 3 2} {4 7 3} {1 5 3} {2 6 2} {7 8 1} {6 8 9} Total: 38
Kruskal's algorithm: {7 8 1} {0 3 2} {2 6 2} {1 5 3} {4 7 3} {0 2 9} {6 8 9} {1 4 9} Total: 38
Boruvka's algorithm: {0 3 2} {1 5 3} {2 6 2} {4 7 3} {7 8 1} {0 2 9} {1 4 9} {6 8

9}
Total: 38
Verticles: 24
Prim's algorithm: {0 1 0} {0 2 0} {0 3 0} {1 4 5} {2 5 8} {2 19 10} {1 20 1} {0 21 0} {0 22 0} {0 23 0}
Total: 24
Kruskal's algorithm: {0 1 0} {0 2 0} {0 3 0} {0 21 0} {0 22 0} {0 23 0} {1 20 1} {1 4 5} {2 5 8} {2 19 10}
Total: 24
Boruvka's algorithm: {0 1 0} {0 2 0} {0 3 0} {1 4 5} {2 5 8} {0 21 0} {0 22 0} {0 23 0} {1 20 1} {2 19 10}
Total: 24
Verticles: 24
Prim's algorithm: {0 1 0} {0 2 0} {0 3 0} {1 4 5} {2 5 8} {2 19 10} {1 20 1} {0 21 0} {0 22 0} {0 23 0}
Total: 24
Kruskal's algorithm: {0 23 0} {0 22 0} {0 21 0} {0 2 0} {0 3 0} {0 1 0} {1 20 1} {1 4 5} {2 5 8} {2 19 10}
Total: 24
Boruvka's algorithm: {0 23 0} {0 1 0} {0 2 0} {0 3 0} {1 4 5} {2 5 8} {0 22 0} {0 21 0} {1 20 1} {2 19 10}
Total: 24
Verticles: 3
Prim's algorithm: {0 1 1} {0 2 1} Total: 2
Kruskal's algorithm: {0 1 1} {0 2 1} Total: 2
Boruvka's algorithm: {0 1 1} {0 2 1} Total: 2
*/
// Special structure "Edge" template <class T>
struct Edge {
int begin, end; T weight;
Edge(int begin = -1, int end = -1, T weight = -1) : begin(begin), end(end), weight(weight) {
if (this->begin > this->end) std::swap(this->begin, this->end);
}
friend bool operator== (const Edge & self, const Edge & arg) { return self.begin == arg.begin && self.end == arg.end;
}
friend bool operator< (const Edge & self, const Edge & arg) { return self.weight < arg.weight;
}

};
//Prim's Algorithm template <class T>
std::pair<std::vector<Edge<T>>, int> primAlgorithm(const std::vector<Edge<T>> & edges, int n) {
if (edges.empty()) return { std::vector<Edge<T>>(), 0 }; const T INF = std::numeric_limits<T>::max(); std::set<std::pair<int, int>> q;
q.insert({ 0, 0 }); std::vector<Edge<T>> st(n); std::vector<T> weights(n, INF); weights[0] = 0; std::vector<bool> inMST(n, false); T stWeight = 0;
while (!q.empty()) {
stWeight += q.begin()->first; int start = q.begin()->second; q.erase(q.begin()); inMST[start] = true;
for (auto & edge : edges) {
int a1 = edge.begin, a2 = edge.end;
if (start == a1 && !inMST[a2] && weights[a2] > edge.weight)
q.erase({ weights[a2], a2 }), q.insert({ weights[a2] = (st[a2] = edge).weight,
a2 });
else if (start == a2 && !inMST[a1] && weights[a1] > edge.weight)
q.erase({ weights[a1], a1 }), q.insert({ weights[a1] = (st[a1] = edge).weight,
a1 });
}
};
st.erase(std::remove_if(st.begin(), st.end(), [] (auto x) { return x.begin < 0; }), st.end());
return { st, stWeight };
}
//Kruskal's Algorithm
template <class T>
std::pair<std::vector<Edge<T>>, int> kruskalAlgorithm(std::vector<Edge<T>> edges, int n) {
if (edges.empty()) return { std::vector<Edge<T>>(), 0 }; std::vector<int> comp(n);
std::vector<Edge<T>> st; std::iota(comp.begin(), comp.end(), 0); std::sort(edges.begin(), edges.end()); T stWeight = 0;
for (auto & edge : edges)
if (comp[edge.begin] != comp[edge.end]) { stWeight += edge.weight; st.emplace_back(edge);

int a = comp[edge.begin], b = comp[edge.end]; for (int i = 0; i < n; ++i)
if (comp[i] == b) comp[i] = a;
}
return { st, stWeight };
}
// Boruvka's Algorithm
struct BoruvkaSubset { int parent, rank; };
int find(std::vector<BoruvkaSubset> & subsets, int i) { // Recursive version:
//if (subsets[i].parent != i)
//subsets[i].parent = find(subsets, subsets[i].parent); //return subsets[i].parent;
//Iterative version:
BoruvkaSubset * f, * m, * temp; int t;
for (f = &subsets[i], t = i; f->parent != t; f = &subsets[t = f->parent]); for (m = &subsets[i], t = i; m->parent != t; )
temp = &subsets[t = m->parent], m->parent = f->parent, m = temp; return subsets[i].parent;
}
template <class T>
std::pair<std::vector<Edge<T>>, int> boruvkaAlgorithm(const std::vector<Edge<T>> & edges, int n) {
if (edges.empty()) return { std::vector<Edge<T>>(), 0 }; int edgesSize = edges.size();
std::vector<Edge<T>> st, cheapest(edgesSize); std::vector<BoruvkaSubset> subsets(n);
for (int i = 0; i < n; ++i)
subsets[i].parent = i, subsets[i].rank = 0; T stWeight = 0;
for (int i = 0; i < n; ++i) {
for (auto & cheap : cheapest) cheap.begin = cheap.end = -1;
for (auto & edge : edges) {
int set1 = find(subsets, edge.begin), set2 = find(subsets, edge.end); if (set1 != set2) {
if (set1 < edgesSize && (cheapest[set1].begin == -1 || cheapest[set1].weight > edge.weight))
cheapest[set1] = edge;
if (set2 < edgesSize && (cheapest[set2].end == -1 || cheapest[set2].weight > edge.weight))
cheapest[set2] = edge;
}
}
for (auto & cheap : cheapest) { if (cheap.begin != -1) {

int set1 = find(subsets, cheap.begin), set2 = find(subsets, cheap.end); if (set1 != set2) {
stWeight += cheap.weight; st.emplace_back(cheap);
int xroot = find(subsets, set1), yroot = find(subsets, set2); if (subsets[xroot].rank < subsets[yroot].rank)
subsets[xroot].parent = yroot;
else if (subsets[xroot].rank > subsets[yroot].rank) subsets[yroot].parent = xroot;
else
++subsets[subsets[yroot].parent = xroot].rank;
}
}
}
}
return { st, stWeight };
}
// Get the number of vertices template <class T>
int getVertices(const std::vector<Edge<T>> & edges) { int max = 0;
for (auto & x : edges)
max = std::max(max, std::max(x.begin, x.end) + 1); return max;
}
Тестирование производится нетривиальным образом… Генерируется граф, который представляется в виде набора ребер. От способа генерации зависит скорость работы того или иного алгоритма построения минимального остова.