Скачиваний:
0
Добавлен:
02.11.2025
Размер:
109.12 Кб
Скачать

Пример работы

Будем создавать лабиринт размером 3 на 3.

Шаг 1.

Инициализация поля три на три. Начало пути находится в левом верхнем углу.

Таблица 3. Алгоритм Прима

Шаг 2.

Согласно алгоритму, выбирается случайная ячейка рядом с уже выбранной, у нас это вторая ячейка.

Шаг 3.

Выбирается следующий случайный пункт.

Шаг 4.

Теперь из этих ячеек случайным образом выбираются следующие. Путь идет вниз в пятую ячейку.

Таблица 4. Алгоритм Прима

Шаг 5.

Из второй ячейки проводится путь в третью. Все уже посещенные ячейки добавляются в множество посещенных, строить путь в них повторно нельзя.

Шаг 6.

Из пятой ячейки путь проводится в четвертую ячейку, она тоже теперь в множестве посещенных, на следующих шагах строить путь в нее нельзя.

Таблица 5. Алгоритм Прима

Шаг 7.

Из третьей ячейки путь может пройти только через шестую ячейку, в нее путь и идет.

Шаг 8.

Из пятого пункта путь может дальше пройти только через восьмую ячейку.

Шаг 9.

Выбирается следующий случайный пункт.

Шаг 10.

Из восьмого пункта путь случайным образом проходит в последний пункт под номером девять.

Таблица 6. Конец алгоритма Прима

Шаг 11.

Принято решение завершить построение лабиринта. Добавим границы лабиринта.

Результаты работы

Графики сложности алгоритмов после тестирования.

На рисунке оранжевым цветом представлен алгоритм Прима, синим – алгоритм Эллера. По графику видно, что при увеличении размерности матрицы для лабиринта (то есть, при увеличении количества границ) время, затрачиваемое на обработку алгоритмов, увеличивается тоже. Но стоит отметить, что на алгоритм Прима времени затрачивается больше, нежели чем на алгоритм Эллера.

Программа

#include <iostream>

#include <vector>

#include <random>

#include <chrono>

#include <set>

#include <algorithm>

#include <numeric>

#include <iomanip>

using namespace std;

struct Cell {

bool visited = false;

bool walls[4] = {true, true, true, true};

int set = -1;

};

class Maze {

private:

int width, height;

vector<vector<Cell>> maze;

random_device rd;

mt19937 gen;

public:

Maze(int w, int h) : width(w), height(h), gen(rd()) {

maze.resize(height, vector<Cell>(width));

}

void generateEller() {

maze = vector<vector<Cell>>(height, vector<Cell>(width));

int setCounter = 0;

for (int row = 0; row < height; row++) {

for (int col = 0; col < width; col++) {

if (maze[row][col].set == -1) {

maze[row][col].set = setCounter++;

}

}

for (int col = 0; col < width - 1; col++) {

bernoulli_distribution join(0.5);

if (join(gen) && maze[row][col].set != maze[row][col + 1].set) {

int oldSet = maze[row][col + 1].set;

int newSet = maze[row][col].set;

maze[row][col].walls[1] = false;

maze[row][col + 1].walls[3] = false;

for (int k = 0; k < width; k++) {

if (maze[row][k].set == oldSet) {

maze[row][k].set = newSet;

}

}

}

}

if (row < height - 1) {

vector<bool> hasVerticalConnection(width, false);

set<int> uniqueSets;

for (int col = 0; col < width; col++) {

uniqueSets.insert(maze[row][col].set);

}

for (int setId : uniqueSets) {

vector<int> setColumns;

for (int col = 0; col < width; col++) {

if (maze[row][col].set == setId) {

setColumns.push_back(col);

}

}

uniform_int_distribution<> dis(0, setColumns.size() - 1);

int selectedCol = setColumns[dis(gen)];

maze[row][selectedCol].walls[2] = false;

maze[row + 1][selectedCol].walls[0] = false;

maze[row + 1][selectedCol].set = maze[row][selectedCol].set;

hasVerticalConnection[selectedCol] = true;

for (int col : setColumns) {

if (col != selectedCol) {

bernoulli_distribution addExtra(0.3);

if (addExtra(gen)) {

maze[row][col].walls[2] = false;

maze[row + 1][col].walls[0] = false;

maze[row + 1][col].set = maze[row][col].set;

hasVerticalConnection[col] = true;

}

}

}

}

}

}

for (int col = 0; col < width - 1; col++) {

if (maze[height-1][col].set != maze[height-1][col + 1].set) {

maze[height-1][col].walls[1] = false;

maze[height-1][col + 1].walls[3] = false;

int oldSet = maze[height-1][col + 1].set;

int newSet = maze[height-1][col].set;

for (int k = col + 1; k < width; k++) {

if (maze[height-1][k].set == oldSet) {

maze[height-1][k].set = newSet;

}

}

}

}

}

void generatePrims() {

maze = vector<vector<Cell>>(height, vector<Cell>(width));

vector<pair<int, int>> frontiers;

maze[0][0].visited = true;

addFrontiers(0, 0, frontiers);

while (!frontiers.empty()) {

uniform_int_distribution<> dis(0, frontiers.size() - 1);

int index = dis(gen);

int row = frontiers[index].first;

int col = frontiers[index].second;

vector<pair<int, int>> neighbors;

if (row > 0 && maze[row-1][col].visited) neighbors.push_back({row-1, col});

if (row < height-1 && maze[row+1][col].visited) neighbors.push_back({row+1, col});

if (col > 0 && maze[row][col-1].visited) neighbors.push_back({row, col-1});

if (col < width-1 && maze[row][col+1].visited) neighbors.push_back({row, col+1});

uniform_int_distribution<> neighborDis(0, neighbors.size() - 1);

auto& neighbor = neighbors[neighborDis(gen)];

if (neighbor.first < row) {

maze[row][col].walls[0] = false;

maze[neighbor.first][neighbor.second].walls[2] = false;

}

else if (neighbor.first > row) {

maze[row][col].walls[2] = false;

maze[neighbor.first][neighbor.second].walls[0] = false;

}

else if (neighbor.second < col) {

maze[row][col].walls[3] = false;

maze[neighbor.first][neighbor.second].walls[1] = false;

}

else {

maze[row][col].walls[1] = false;

maze[neighbor.first][neighbor.second].walls[3] = false;

}

maze[row][col].visited = true;

frontiers.erase(frontiers.begin() + index);

addFrontiers(row, col, frontiers);

}

}

private:

void addFrontiers(int row, int col, vector<pair<int, int>>& frontiers) {

vector<pair<int, int>> directions = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};

for (auto& dir : directions) {

int newRow = row + dir.first;

int newCol = col + dir.second;

if (newRow >= 0 && newRow < height && newCol >= 0 && newCol < width

&& !maze[newRow][newCol].visited) {

frontiers.push_back({newRow, newCol});

}

}

}

};

struct TestResults {

double ellerAvg;

double primsAvg;

long long ellerMin;

long long ellerMax;

long long primsMin;

long long primsMax;

};

int main() {

const int iterations = 1000;

const int minSize = 5;

const int maxSize = 30;

const int step = 2;

// Создаем вектор для хранения результатов для каждого размера

vector<TestResults> allResults;

cout << "Начало тестирования...\n\n";

// Проходим по всем размерам от 5 до 30 с шагом 2

for(int size = minSize; size <= maxSize; size += step) {

cout << "Тестирование размера " << size << "x" << size << "...\n";

vector<long long> ellerTimes(iterations);

vector<long long> primsTimes(iterations);

Maze maze(size, size);

// Выполняем тесты для текущего размера

for(int i = 0; i < iterations; i++) {

// Тест алгоритма Эллера

auto start = chrono::high_resolution_clock::now();

maze.generateEller();

auto end = chrono::high_resolution_clock::now();

ellerTimes[i] = chrono::duration_cast<chrono::microseconds>(end - start).count();

// Тест алгоритма Прима

start = chrono::high_resolution_clock::now();

maze.generatePrims();

end = chrono::high_resolution_clock::now();

primsTimes[i] = chrono::duration_cast<chrono::microseconds>(end - start).count();

}

// Вычисляем статистику

TestResults results;

results.ellerAvg = accumulate(ellerTimes.begin(), ellerTimes.end(), 0.0) / iterations;

results.primsAvg = accumulate(primsTimes.begin(), primsTimes.end(), 0.0) / iterations;

auto ellerMinMax = minmax_element(ellerTimes.begin(), ellerTimes.end());

auto primsMinMax = minmax_element(primsTimes.begin(), primsTimes.end());

results.ellerMin = *ellerMinMax.first;

results.ellerMax = *ellerMinMax.second;

results.primsMin = *primsMinMax.first;

results.primsMax = *primsMinMax.second;

allResults.push_back(results);

}

// Выводим результаты в виде таблицы

cout << "\nРезультаты тестирования:\n\n";

cout << setw(10) << "Размер"

<< setw(15) << "Эллер ср."

<< setw(15) << "Эллер мин."

<< setw(15) << "Эллер макс."

<< setw(15) << "Прим ср."

<< setw(15) << "Прим мин."

<< setw(15) << "Прим макс."

<< setw(15) << "Разница %" << endl;

cout << string(115, '-') << endl;

for(int i = 0, size = minSize; size <= maxSize; size += step, i++) {

double diffPercent = ((allResults[i].primsAvg - allResults[i].ellerAvg)

/ allResults[i].primsAvg * 100);

cout << setw(8) << size << "x" << size

<< setw(15) << fixed << setprecision(2) << allResults[i].ellerAvg

<< setw(15) << allResults[i].ellerMin

<< setw(15) << allResults[i].ellerMax

<< setw(15) << allResults[i].primsAvg

<< setw(15) << allResults[i].primsMin

<< setw(15) << allResults[i].primsMax

<< setw(15) << diffPercent << "%" << endl;

}

return 0;

}

Санкт-Петербург

2025