Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Лабы по ПиАА 2024 / Baraeva_Elizaveta_lb1

.doc
Скачиваний:
0
Добавлен:
09.09.2026
Размер:
121 Кб
Скачать

МИНОБРНАУКИ РОССИИ

Санкт-Петербургский государственный

электротехнический университет

«ЛЭТИ» им. В. И. Ульянова (Ленина)

Кафедра МО ЭВМ

отчет

по лабораторной работе №1

по дисциплине «Построение и анализ алгоритмов»

Тема: Поиск с возвратом

Студентка гр. 2383

Бараева Е. Н.

Преподаватель

Шевелева А. М.

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

2024

Цель работы.

Изучить информацию об алгоритме поиска с возвратом. Решить поставленную задачу, используя алгоритм поиска с возвратом, на языке C++.

Задание.

У Вовы много квадратных обрезков доски. Их стороны (размер) изменяются от 1 до N−1, и у него есть неограниченное число обрезков любого размера. Но ему очень хочется получить большую столешницу - квадрат размера N. Он может получить ее, собрав из уже имеющихся обрезков(квадратов).

Например, столешница размера 7×7 может быть построена из 9 обрезков.

Рисунок 1 – Пример столешницы

Внутри столешницы не должно быть пустот, обрезки не должны выходить за пределы столешницы и не должны перекрываться. Кроме того, Вова хочет использовать минимально возможное число обрезков.

Входные данные

Размер столешницы - одно целое число N (2≤N≤20).

Выходные данные

Одно число K, задающее минимальное количество обрезков(квадратов), из которых можно построить столешницу(квадрат) заданного размера N. Далее должны идти K строк, каждая из которых должна содержать три целых числа, x,y и w, задающие координаты левого верхнего угла (1≤x,y≤N) и длину стороны соответствующего обрезка(квадрата).

Вариант 1.

Выполнить исследование задачи на изменение времени поиска решения в зависимости от размера квадрата.

Основные теоретические положения.

Данную задачу можно разделить на 2 случая: длина столешницы – составное или простое число. Для составных четных чисел количество досок будет 4, а их длина N / 2. Для составных нечетных числе задача сводится к нахождению минимального простого делителя и поиску для него решения, а затем домножения этого решения на N / min_div. А для простых чисел разумнее всего расположить 3 квадрата размеров (N + 1) / 2, (N - 1) / 2, (N - 1) / 2 в три угла так, чтобы два маленьких квадрата соприкасались сторонами с большим. Затем для оставшейся фигуры искать решение.

Выполнение работы.

  • void data_optimization() – функция, которая преобразовывает данные: ищет коэффициент домножения ответа, уменьшает размер поля, рисует первые 3 квадрата на карте и добавляет их координаты и размер в массив для ответа.

  • int min_div(int x) – функция поиска минимального простого делителя.

  • void set_square(int x, int y, int w, int setter) – функция рисовки или стирания квадрата на карте.

  • int check_square(int x, int y, int w) – функция проверки места для расположения квадрата.

  • void backtracking(int coord) – рекурсивная функция, которая ищет лучшее решение расположения квадратов в оставшемся месте. В начале двигается координата до ближайшего пустого места. Затем проверяется, не дошли ли до конца, если да, то осуществляется проверка пустоты и оптимальности ответа, перезапись его (если нужно) и возврат из функции. После функция высчитывает координаты, размер помещающегося квадрата, рисует его, записывая координаты в ответ, и вызывает себя. В конце квадрат стирается и координаты его тоже.

  • int main() – в функции считывается размер столешницы, карта заполняется нулями, вызывается data_optimization, backtracking и void output().

  • void output() – функция выводит ответ на экран.

Разработанный программный код см. в приложении А.

Тестирование.

Результаты тестирования представлены в табл. 1.

Таблица 1 – Результаты тестирования

№ п/п

Входные данные

Выходные данные

Комментарии

1.

7

9

1 1 4

1 5 3

5 1 3

4 5 2

4 7 1

5 4 1

5 7 1

6 4 2

6 6 2

Простое число. Верно.

2.

9

6

1 1 6

1 7 3

7 1 3

4 7 3

7 4 3

7 7 3

Составное нечетное число. Верно.

3.

16

4

1 1 8

1 9 8

9 1 8

9 9 8

Составное четное число. Верно.

4.

23

13

1 1 12

1 13 11

13 1 11

12 13 2

12 15 5

12 20 4

13 12 1

14 12 3

16 20 1

16 21 3

17 12 7

17 19 2

19 19 5

Простое число. Верно.

Исследование.

Результаты исследования работы алгоритма представлены в табл. 2.

Таблица 2 – Результаты исследования

N

sec

2

0,0000084

3

0,0000101

4

0,0000099

5

0,0000134

6

0,0000112

7

0,0000184

8

0,0000118

9

0,0000137

10

0,0000130

11

0,0000726

12

0,0000130

13

0,0001574

14

0,0000141

15

0,0000174

16

0,0000168

17

0,0009365

18

0,0000224

19

0,0025387

20

0,0000235

21

0,0000246

22

0,0000232

23

0,0095506

24

0,0000236

25

0,0000272

26

0,0000243

27

0,0000265

28

0,0000256

29

0,0670108

30

0,0000256

31

0,1571048

32

0,0000267

33

0,0000296

34

0,0000292

35

0,0000319

36

0,0000310

37

0,8320149

38

0,0000321

39

0,0000383

40

0,0000377

График отношения размера столешницы ко времени работы алгоритма см. рис. 2.

Рисунок 2 – График исследования

По графику можно сделать вывод о том, что значение в составных числах максимально приближены к нулю, а также о том, что наибольшее значение времени достигается на больших простых числах (23, 29, 31, 37). Это связно с тем, что не получается оптимизировать данные с заменой числа на его наименьший простой делитель.

Вывод.

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

Для оптимизации алгоритма было вычислено разбиения только для простых чисел, а для составных чисел ответ домножался на коэффициент. Также перед алгоритмом всегда расстанавливались три квадрат размерами: (N + 1) / 2, (N - 1) / 2, (N - 1).

Еще было проведено исследование роста времени выполнения алгоритма при увеличении размера квадрата. Результаты показали, что худший случай алгоритма – большое простое число. Лучший случай – составное число, которое можно сократить до наименьшего простого, что в разы уменьшает время работы программы. Сложность алгоритма по времени является экспоненциальной.

ПРИЛОЖЕНИЕ А ИСХОДНЫЙ КОД ПРОГРАММЫ

Название файла: main.cpp

#include <iostream>

#include <vector>

#include <array>

#include <cmath>

int N, n, k = 0, cell_count = 0;

std::vector<std::array<int,3>> answer, curr_answer;

std::vector<std::vector<int>> map;

int min_div(int x) {

if (x % 2 == 0)

return 2;

for (int i = 3; i < int(sqrt(x)) + 1; i += 2)

if (x % i == 0)

return i;

return x;

}

void set_square(int x, int y, int w, int setter) {

for (int i = x; i < x + w; i++)

for (int j = y; j < y + w; j++)

map[i][j] = setter;

}

int check_square(int x, int y, int w) {

if (y + w > n or x + w > n)

return 0;

for (int i = x; i < x + w; i++)

for (int j = y; j < y + w; j++)

if (map[i][j])

return 0;

return 1;

}

void backtracking(int coord) {

if (coord < cell_count)

while (map[coord / n][coord % n]) {

coord++;

if (coord == cell_count)

break;

}

if (coord == cell_count) {

if (answer.empty() or curr_answer.size() < answer.size())

answer = curr_answer;

return;

}

if (answer.empty() or curr_answer.size() + 1 < answer.size()) {

int x = coord / n;

int y = coord % n;

int max_square = std::min(n - x, n - y);

while (not check_square(x, y, max_square))

max_square--;

for (int size_square = max_square; size_square > 0; size_square--) {

set_square(x, y, size_square, 1);

curr_answer.push_back({x, y, size_square});

backtracking(coord + size_square);

set_square(x, y, size_square, 0);

curr_answer.pop_back();

}

}

}

void data_optimization() {

k = n / min_div(n);

n /= k;

cell_count = n * n;

set_square(0, 0, (n + 1) / 2, 1);

set_square(0, (n + 1) / 2, n / 2, 1);

set_square((n + 1) / 2, 0, n / 2, 1);

curr_answer.push_back({0, 0, (n + 1) / 2});

curr_answer.push_back({0, (n + 1) / 2, n / 2});

curr_answer.push_back({(n + 1) / 2, 0, n / 2});

}

void output() {

std::cout << answer.size() << std::endl;

for (int i = 0; i < answer.size(); i++)

std::cout << answer[i][0] * k + 1 << " " << answer[i][1] * k + 1 << " " << answer[i][2] * k << std::endl;

}

int main() {

std::cin >> N;

n = N;

for (int i = 0; i < N; i++)

map.emplace_back(N, 0);

data_optimization();

backtracking(0);

output();

return 0;

}

9

Соседние файлы в папке Лабы по ПиАА 2024