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
24 changes: 24 additions & 0 deletions src/hw_queens/complexity.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Оценка сложности решений задачи о расстановке ферзей

## 1. Переборное решение
- Очень медленное решение
- all_cells содержит n^2 элементов (все клетки доски), и при помощи combinations получаем C(n^2, n)
- is_valid в худшем случае даст n^2 операций
Итог: О(С(n^2,n) * n^2)
Copy link

Choose a reason for hiding this comment

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

Можно писать формулки как в latex, если обернуть их в $$
$O(C^{n^2}_n \cdot n^2)$

Позволяет получить получить решения для n<=6



## 2. Рекурсивное решение
- Рекурсия - n!
- Проверка на валидность - n^2
Итог: O(n! * n^2)
Позволяет получить получить решения для n<=8



## 3. Самое быстрое решение
- Рекурсия - n!
- Проверка наличия элементов во всех множествах, добавление/удаление из sets: O(1)
Итог: O(n!)
Позволяет получить получить решения для n<=13-14
31 changes: 31 additions & 0 deletions src/hw_queens/fastest_queens.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
def queens_counter(n):
columns = set()
diag1 = set()
diag2 = set()

def backtrack(row):
if row == n:
return 1 # нашли +1 решение

count = 0
for col in range(n):
if col in columns or (row + col) in diag1 or (row - col) in diag2:
continue

columns.add(col)
diag1.add(row + col) # диагонали слева направо (/)
diag2.add(row - col) # диагонали справа налево (\)

count += backtrack(row + 1) # суммируем решения из этой ветки

columns.remove(col)
diag1.remove(row + col)
diag2.remove(row - col)

return count

return backtrack(0) # Рекурсия

n = int(input("Введите n: ")) # Можно до 13-ти включительно, 14 выдает меньше чем за полминуты
result = queens_counter(n)
print(f"Количество расстановок {n} ферзей: {result}")
33 changes: 33 additions & 0 deletions src/hw_queens/itertools_queens.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import itertools

# Функция для проверки того, что ферзи не бьют друг друга, то есть расстановка валидная
def is_valid(cords, n):
# Проверяем строки
for i in range(n):
for j in range(i + 1, n):
# Если два ферзя в одной строке
if cords[i][0] == cords[j][0]:
return False
# Если два ферзя в одном столбце
if cords[i][1] == cords[j][1]:
return False
# Если два ферзя на одной диагонали
if abs(cords[i][0] - cords[j][0]) == abs(cords[i][1] - cords[j][1]):
return False
return True

def queens_counter(n):
count = 0 # Счетчик правильных расстановок ферзей

# Генерируем все возможные наборы из N различных клеток
all_cells = [(i, j) for i in range(n) for j in range(n)]

# Возьмем все расстановки без повторяющихся клеток
for cords in itertools.combinations(all_cells, n):
Copy link

Choose a reason for hiding this comment

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

Вместо combinations по всем клеткам используй permutations для столбцов. Так перебор сократиться с 4.4 млрд до 40 тысяч вариантов (для N=8).

if is_valid(cords, n):
count += 1
return count

n = int(input("Введите n: ")) # Можно до 6-ти, 7 уже не тянет (ждала больше минуты)
result = queens_counter(n)
print(f"Количество расстановок {n} ферзей: {result}")
37 changes: 37 additions & 0 deletions src/hw_queens/recursive_queens.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Функция для проверки того, что ферзи не бьют друг друга, то есть расстановка валидная
def is_valid(cords, n):
# Проверяем строки и столбцы
rows = [q[0] for q in cords]
columns = [q[1] for q in cords]
if len(set(rows)) != n or len(set(columns)) != n:
return False

# Проверяем диагонали
for i in range(n):
for j in range(i + 1, n):
if abs(cords[i][0] - cords[j][0]) == abs(cords[i][1] - cords[j][1]):
return False
return True


def queens_counter(row, n, placed_queens):
count = 0
if row == n: # Если дошли до конца доски, то завершаем
if is_valid(placed_queens, n):
return 1
return 0

for column in range(n):
if (row, column) not in placed_queens: # Проверка, чтобы не было двух (0,1)
new = placed_queens + [(row, column)]
count += queens_counter(row + 1, n, new)
Comment on lines +25 to +27
Copy link

Choose a reason for hiding this comment

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

Нужно было добавить тут проверку is_valid, тогда, если перестановка уже в текущем виде не валидна, мы её отбросим. Сейчас сначала заполняется поле, а после выполняется проверка валидности, что не имеет особого смысла.

return count


def count_queens_recursive(n):
return queens_counter(0, n, [])


n = int(input("Введите n: ")) #Можно до 7-ми быстро, 8 выдает у меня за секунд 15
result = count_queens_recursive(n)
print(f"Количество расстановок {n} ферзей: {result}")