Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions src/06oct25/complexity.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
## Переборный алгоритм
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Можно значительно лучше с точки зрения асимптотики

### Скорость
Количество комбинаций во внешнем цикле $C_{n^2}^{n} = \frac{(n^2)!}{((n^2−n)!(n^2)!)}$.
Внутри вычисление rows и columns за $O(n)$.
Проверка диагоналей за $O(n^2)$ и прямых за 2 * O(n).
Итоговая сложность $O(\frac{n^2 * n^2!}{n! * (n^2-n)!})$.
$\to O(\frac{n^{2n+2}}{n!})$

## Рекурсивный алгоритм
### Скорость
Глубина рекурсии n.
В каждом вызове перебирается n вариантов.
Проверкка выполняется за O(n). Итоговая сложность O(n * n^2) = O(n^3).
Comment on lines +11 to +13
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

### Память
Рекурсия O(n) и O(n). Общая O(n)

## Третий алгоритм
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Кажется, что вы не проявили социальность. Предполагается другое

### Скорость
Перебирается n, n-1, n-2 и т.д. решений, в каждом из них проверка O(n). В итоге O(n * n!)
### Память
Глубина рекурсии O(n), все переменные занимают O(1). Итого O(n)
26 changes: 26 additions & 0 deletions src/06oct25/queen_permutation_v1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
from itertools import combinations

def check_queen_combination(cell_numbers, n):
rows = [cell // n for cell in cell_numbers]
columns = [cell % n for cell in cell_numbers]
for i in range(1, n):
for j in range(i):
# проверяем что не на одной диагонали
if abs(rows[i] - rows[j]) == abs(columns[i] - columns[j]):
return False
if len(set(rows)) != n:
return False # если есть свопадающие ряды
if len(set(columns)) != n:
return False # если есть совпадающие колонки
return True

def queen_permutations(n):
count = 0
# номера клеток с ферзем слева направо сверху вниз
for cell_numbers in combinations(range(n * n), n):
if check_queen_combination(cell_numbers, n):
count += 1
return count

if __name__ == "__main__":
print(queen_permutations(7))
25 changes: 25 additions & 0 deletions src/06oct25/queen_permutation_v2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
def queen_permutations(n):
def helper(row, board):
# если все ферзи расставлены найдено корректное решение
if row == n:
return 1
count = 0
# пробуем поставить ферзя в каждом столбце текущей строки
for column in range(n):
correct = True
# проверка что с новым ферзем все остается нормально
for i in range(row):
if board[i] == column or board[i] - i == column - row or board[i] + i == column + row:
correct = False
break
if correct:
board[row] = column
# добавляем к счетчику все комбинции ферзя со следующего ряда
count += helper(row + 1, board)
return count

# начинаем с первого ряда и пустой доски
return helper(0, [-1] * n)

print(queen_permutations(7))

33 changes: 33 additions & 0 deletions src/06oct25/queen_permutation_v3.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
def queen_permutations(n):
def backtrack(row, columns, diag1, diag2):
"""
один шаг подсчета расстановок
:param row: номер ряда, на котором мы фокусируемся
:param columns: занятые колнки в двоичном числе. 0 - свободно, 1 - занято
:param diag1: двоичное число диагонали в обозначении ряд + колнка
:param diag2: двоичное число диагонали ряд - колонка
:return: количество расстановок с текущего ряда
"""
if row == n:
return 1
count = 0
# число, обозначающее занятые позиции. в начале это n единиц
all_positions = (1 << n) - 1
# объединяем все недоступные поля (которые биты двоичного числа)
attacked = columns | diag1 | diag2
# убираем из всех единиц недоступные и получаем доступные поля
available = all_positions & ~attacked
# выбираем свободные позиции пока такие есть
while available:
# самый правый в свободных бит (- меняет все 1 на 0 и дабавляет 1)
cell = available & -available
# убираем его из свободных
available -= cell
# ищем расстановки с уже занятой этой клеткой для следующего ряда
count += backtrack(row + 1, columns | cell, (diag1 | cell) << 1, (diag2 | cell) >> 1)
return count
# вначале доска пустая
return backtrack(0, 0, 0, 0)

if __name__ == "__main__":
print(queen_permutations(7))