Добавил:
СПбГУТ * ИКСС * Программная инженерия Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Коды основных функций / [Код основных функций] Лаб. 4

.pdf
Скачиваний:
44
Добавлен:
03.08.2020
Размер:
64.7 Кб
Скачать

[Код основных функций] Лабораторная работа №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;

}

Тестирование производится нетривиальным образом… Генерируется граф, который представляется в виде набора ребер. От способа генерации зависит скорость работы того или иного алгоритма построения минимального остова.