Форум программистов, компьютерный форум, киберфорум
Python для начинающих
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.70/64: Рейтинг темы: голосов - 64, средняя оценка - 4.70
705 / 351 / 104
Регистрация: 09.02.2018
Сообщений: 798
1

Количество расстановок N ферзей на шахматной доске N×N

30.12.2020, 15:05. Показов 12420. Ответов 17

Author24 — интернет-сервис помощи студентам
Требуется подсчитать количество расстановок N ферзей на шахматной доске N×N таким образом, чтобы никакие два ферзя не били друг друга.
Расстановка ферзей таким образом называется мирной. Например, для доски 8×8 существует 92 различные мирные расстановки ферзей.

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

Вводится единственное натуральное число N (1 <= N <= 12).

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

Выведите искомое количество мирных расстановок ферзей.

Пример:


Ввод: 8
Вывод: 92

Ограничения:

Время: 1 с
Память: 64 Мб

Добавлено через 2 часа 53 минуты
Вот что набросал:

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
from itertools import permutations
n = int(input())
queens = [None] * n
k = 0
#Перебор перестановок ферзей по столбцам.
for perm in permutations(range(n)):
    #Начальное предположение, что позиция верная
    #(увеличивем счетчик количества позиций).
    k += 1
    #Для каждого ферзя считаем номер
    #главной и побочной диагоналей,
    #на которых он находится.
    for i in range(n):
        j = perm[i]
        queens[i] = (i + j, i - j)
    #Проверяем, что ферзи не бьют
    #друг друга по диагоналям.
    f = False
    for i in range(n - 1):
        idiag, isdia = queens[i]
        for j in range(i + 1, n):
            jdiag, jsdia = queens[j]
            if idiag == jdiag or \
               isdia == jsdia:
                   #Предположение о корректности
                   #позиции не оправдалось,
                   #уменьшаем счетчик количества
                   #позиций и ставим флаг.
                   k -= 1
                   f = True
                   break
        if f: break
print(k)
Проходит только 8 тестов из 12. Последние 4 теста не проходит по времени.

Посоветуйте что-нибудь.

Добавлено через 2 минуты
Добавлено через 2 часа 53 минуты
Жесть, прошло 2 часа 53 минуты, а я решил только одну задачу. Где там Gdez, который уверял, что это "семечки"?
0
Лучшие ответы (1)
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
30.12.2020, 15:05
Ответы с готовыми решениями:

Расстановка N ферзей на шахматной доске N×N
Требуется расставить N ферзей на шахматной доске N×N таким образом, чтобы никакие два ферзя не били...

Количество расстановок нескольких (K) ферзей на шахматной доске N×N
Требуется подсчитать количество расстановок K ферзей на шахматной доске N×N таким образом, чтобы...

Получить m расстановок 8 ферзей на шахматной доске, при которых ни один из ферзей не угрожает другому
10. Дано натуральное число m. Получить m расстановок 8 ферзей на шахматной доске, при которых ни...

Получить m расстановок 8 ферзей на шахматной доске
Дано натуральное число m. Получить m расстановок 8 ферзей на шахматной доске, при которых ни один...

17
Эксперт Python
8214 / 4334 / 1837
Регистрация: 27.03.2020
Сообщений: 7,157
30.12.2020, 16:12 2
КулХацкеръ, ссылка на тестер есть?
0
705 / 351 / 104
Регистрация: 09.02.2018
Сообщений: 798
30.12.2020, 17:23  [ТС] 3
Gdez, да, вот ссылка:

https://www.e-olymp.com/ru/problems/2712
0
Эксперт Python
8214 / 4334 / 1837
Регистрация: 27.03.2020
Сообщений: 7,157
30.12.2020, 18:49 4
КулХацкеръ, Не получается 10 . Нужна рекурсия. Я в ней как то никак
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def test(k, arr):
    return k not in arr and all(abs(k - x) != len(arr) - i for i, x in enumerate(arr))
 
 
def fun(n):
    desk = [[]]
    for _  in range(n):
        desk = [pos + [i + 1] for pos in desk
                     for i in range(n) if test(i + 1, pos)]
        #print(desk)
         
    print(len(desk))
 
n = int(input())
fun(n)
1
705 / 351 / 104
Регистрация: 09.02.2018
Сообщений: 798
30.12.2020, 19:43  [ТС] 5
Gdez, аналогично. Сумел улучшить свой результат до 10 тестов из 12, но не более того.

Спасибо большое за вариант, он гораздо красивее моего.

Добавлено через 29 минут
Нужна рекурсия.
Кстати, мое решение, что прошло 10 тестов, было именно рекурсивное, основанное на замечании от dondublon. Но пару тестов все равно не прошло.
0
3572 / 2173 / 570
Регистрация: 02.09.2015
Сообщений: 5,490
30.12.2020, 20:04 6
Цитата Сообщение от КулХацкеръ Посмотреть сообщение
Сумел улучшить свой результат до 10 тестов из 12
Остальные 2 TL (timelimit)? Сделай прекеш (посчитай вручную или с помощью программы результат для 1 <= n <= 12) и возвращай результат.
P. S. Стата говорит, что решений на Python'е нет.
P. P. S. А остальные решения за 0 ms явно указывают на то, что так и нужно было. Быстрее чем O(1) не написать решение.
0
705 / 351 / 104
Регистрация: 09.02.2018
Сообщений: 798
30.12.2020, 20:38  [ТС] 7
Arsegg, да, остальные два теста - лимит времени.
0
Эксперт Python
8214 / 4334 / 1837
Регистрация: 27.03.2020
Сообщений: 7,157
30.12.2020, 20:43 8
КулХацкеръ, может с рекурсией у тебя получше, чем у меня?
Просто как то летом решал на информатиксе => там до 10.
0
705 / 351 / 104
Регистрация: 09.02.2018
Сообщений: 798
31.12.2020, 00:09  [ТС] 9
Gdez, если смотреть по времени - то да, мое решение с рекурсией получше. На 11 тесте время примерно четверть секунды (у тебя примерно три четверти секунды).

Код такой:

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
k = 0
n = int(input())
#Изначально отмечаем все клетки доски
#как доступные для размещения ферзя.
available_cells = set()
for i in range(n):
    for j in range(n):
        available_cells.add((i, j))
#Перебираем все размещения первого
#ферзя на столбцах первой строки,
#второго ферзя на столбцах второй
#строки и так далее, а в качестве
#критерия, что ферзь не попадает
#под бой, используем данные из
#множества доступных клеток
#для текущего шага алгоритма.
def put_queen(row, available_cells):
    global k
    for column in range(n):
        if (row, column) in available_cells:
            if row == n - 1: #Если последняя строка...
                k += 1
            else:
                available_cells2 = available_cells.copy()
                #Вычеркиваем вертикаль.
                for i in range(row, n):
                    t = (i, column)
                    if t in available_cells2:
                        available_cells2.remove((i, column))
                #Вычеркиваем диагонали.
                i, j = row, column
                while i < n and j > -1:
                    t = (i, j)
                    if t in available_cells2:
                        available_cells2.remove(t)
                    i += 1
                    j -= 1
                i, j = row, column
                while i < n and j < n:
                    t = (i, j)
                    if t in available_cells2:
                        available_cells2.remove(t)
                    i += 1
                    j += 1
                #Проверяем следующую строку.
                put_queen(row + 1, available_cells2)
put_queen(0, available_cells)
print(k)
Добавлено через 10 минут
Да, Arsegg, посмотрел другие решения, и судя по времени, некоторые не гнушались грязных хаков. Чего-нибудь вроде этого, я так думаю:

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
print(
[0,
1,
0,
0,
2,
10,
4,
40,
92,
352,
724,
2680,
14200,
73712,
365596,
2279184,
14772512,
95815104,
666090624,
4968057848,
39029188884,
314666222712,
2691008701644,
24233937684440,
227514171973736,
2207893435808352,
22317699616364044,
234907967154122528,][int(input())])
Но это несерьезно. Лучше попробую переписать свое рекурсивное решение на C++.

Добавлено через 1 час 14 минут
Ссылка на еще один вариант решения данной задачи, автор Catstail.

Добавлено через 1 час 55 минут
Переписал свой код на C, довольно корявенько (ведь я не умею программировать на этом языке).

Программа прошла все тесты за 654 мс, я в полном шоке!! Не думал, что C настолько быстрее Python, особенно в столь неумелых руках, как мои.

Решение на C:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
#include <stdio.h>
#include <stdlib.h>
 
struct point
{
    int x;
    int y;
};
 
int n, m, positions_count;
 
int is_avaiable(struct point target_cell, int* available_cells)
{
    return available_cells[n * target_cell.x + target_cell.y] == 0;
}
 
void remove_cell(struct point target_cell, int* available_cells)
{
    available_cells[n * target_cell.x + target_cell.y] = -1;
}
 
void copy(int* available_cells, int* available_cells2)
{
    for (int k = 0; k < m; k++)
        available_cells2[k] = available_cells[k];
}
 
void put_queen(int row, int* available_cells)
{
    int i, j, pos;
    struct point current_cell, temp_cell;
    int* available_cells2;
    available_cells2 = (int*) malloc(m * sizeof(int));
    current_cell.x = row;
    for (int column = 0; column < n; column++)
    {
        current_cell.y = column;
        if (is_avaiable(current_cell, available_cells))
            if (row == n - 1) positions_count++;
            else
            {
                copy(available_cells, available_cells2);
                temp_cell.y = column;
                for (i = row; i < n; i++)
                {
                    temp_cell.x = i;
                    remove_cell(temp_cell, available_cells2);
                }
                for (i = row, j = column; (i < n) && (j > -1); i++, j--)
                {
                    temp_cell.x = i;
                    temp_cell.y = j;
                    remove_cell(temp_cell, available_cells2);
                }
                for (i = row, j = column; (i < n) && (j < n); i++, j++)
                {
                    temp_cell.x = i;
                    temp_cell.y = j;
                    remove_cell(temp_cell, available_cells2);
                }
                put_queen(row + 1, available_cells2);
            }
    }
    free(available_cells2);
}
 
int count_positions()
{
    int i, j, k;
    int* available_cells;
    m = n * n;
    available_cells = (int*) malloc(m * sizeof(int));
    k = 0;
    for (i = 0; i < n; i++)
        for(j = 0; j < n; j++)
        {
            available_cells[k] = 0;
            k++;
        }
    positions_count = 0;
    put_queen(0, available_cells);
    free(available_cells);
    return positions_count;
}
 
void solve()
{
    scanf("%d", &n);
    printf("%d", count_positions());
}
 
int main()
{
    solve();
    return 0;
}
0
Arsegg
31.12.2020, 00:17
  #10

Не по теме:

Цитата Сообщение от КулХацкеръ Посмотреть сообщение
Программа прошла все тесты за 654 мс, я в полном шоке!! Не думал, что C настолько быстрее Python.
Ничего удивительного. На Python'е можно решить лишь единичные олимпиадные задачи. На Java чуть более, где нет активного ввода/вывода. На C/C++ (раньше Pascal) решаются остальные.

0
494 / 340 / 134
Регистрация: 14.06.2016
Сообщений: 660
31.12.2020, 00:46 11
Доска симметричная.
0
Эксперт Python
8214 / 4334 / 1837
Регистрация: 27.03.2020
Сообщений: 7,157
31.12.2020, 07:58 12
Лучший ответ Сообщение было отмечено КулХацкеръ как решение

Решение

КулХацкеръ, http://www.ic-net.or.jp/home/takaken/e/queen/
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
def Backtrack(y, left, down, right) :
    global SIZE
    global MASK
    global COUNT
 
    if y == SIZE :
        COUNT += 1
    else :
        bitmap = MASK & ~(left | down | right)
        while bitmap :
            bit = -bitmap & bitmap
            bitmap ^= bit
            Backtrack(y+1, (left | bit)<<1, down | bit, (right | bit)>>1)
            
            
SIZE = int(input())    # N
COUNT = 0                # result
 
MASK = (1 << SIZE) - 1
Backtrack(0, 0, 0, 0)
 
print(COUNT)
921 ms
Но не мои
0
Модератор
Эксперт функциональных языков программированияЭксперт Python
36606 / 20334 / 4221
Регистрация: 12.02.2012
Сообщений: 33,653
Записей в блоге: 13
31.12.2020, 09:13 13
Gdez, ну конечно же бэктрекинг!
0
Эксперт Python
8214 / 4334 / 1837
Регистрация: 27.03.2020
Сообщений: 7,157
31.12.2020, 09:30 14
Catstail, А скорость за счет битовых операций?
По сравнению с Вашим кодом
0
Модератор
Эксперт функциональных языков программированияЭксперт Python
36606 / 20334 / 4221
Регистрация: 12.02.2012
Сообщений: 33,653
Записей в блоге: 13
31.12.2020, 09:39 15
Gdez, конечно, битовые операции быстрее! Мой код слишком "разлапист", но более нагляден. Есть подозрение, что мой код можно ускорить за счет того, что исключить многократный вызов mark_fld (т.е. втянуть эту функцию внутрь queen). Это ускорит код, но противоречит правильным принципам программирования...
0
Эксперт Python
8214 / 4334 / 1837
Регистрация: 27.03.2020
Сообщений: 7,157
31.12.2020, 09:51 16
Catstail, В том коде симметричность, да и идет поиск числа "правильных" позиций без запоминания расположения плюс они "растянули" доску в одномерную последовательность.
А так, Ваш код, конечно, понятнее. Но все равно пока мне очень далеко до этого уровня
1
Catstail
31.12.2020, 12:17
  #17

Не по теме:

Gdez, нам всем есть куда расти! Успехов в новом году!

0
0 / 0 / 0
Регистрация: 05.03.2022
Сообщений: 2
21.12.2023, 08:06 18
#include <iostream>

using namespace std;

int kol = 0;
const int n = 8;
bool a[n][n];
void ans(int n) {
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
cout << a[i][j] << '\t';
}
cout << endl;
}
}
bool logic(int str, int st) {
for (int i = 0; i < str; i++) { // проверка столбца
/*if (a[i][str] == 1)
return 0;*/
if (a[st][i] == 1)
return 0;
}
int strx = str, sty = st;

while (str > 0 && st > 0) {// проверка главной диагонали
if (a[st - 1][str - 1] == 1)
return 0;
str--;
st--;
}
while (strx > 0 && sty < n - 1) { //проверка побочной диагонали
if (a[sty + 1][strx - 1] == 1)
return 0;
strx--;
sty++;
}
return 1;
}
void board(int str) {
if (str == n) {
kol++;
ans(n);
cout << endl;
return;
}
for (int i = 0; i < n; i++) {
if (logic(str, i)) {
a[i][str] = 1;
board(str + 1);
a[i][str] = 0;
}
}
}

int main()
{
board(0);
cout << kol;
}
0
21.12.2023, 08:06
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
21.12.2023, 08:06
Помогаю со студенческими работами здесь

Рекурсия: найти количество всевозможных различных расстановок n ферзей на доске n*n
Дана шахматная доска размера n*n. Найдите количество всевозможных различных расстановок n ферзей на...

Определить количество расстановок ладей на шахматной доске
какое кол-во способ расставить ладей на шахматную доску, так чтобы они били все свободные поля?

Разместить на шахматной доске 8х8 максимальное количество ферзей
Помогите написать функцию в VBA Задача: разместить на шахматной доске 8х8 максимальное количество...

Вывести максимальное количество ферзей, которых можно расставить на шахматной доске
Вероятно, многие из вас играли в шахматы. Поэтому вы знаете, что ферзь может двигаться как по...

8 ферзей на шахматной доске
раставить 8 ферзей на доске с помощью oracle sql (1 запросом) Добавлено через 34 секунды with...

Расстановка ферзей на шахматной доске
Найти на кубической доске всевозможные расстановки 15 ферзей так, чтобы они не били друг друга

Расположить на шахматной доске 8 ферзей
Доброго времени суток! Помогите, пожалуйста, с решением: Расположить на шахматной доске 8 ферзей...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
18
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru