#java #recursion #n-queens
#java #рекурсия #n-queens
Вопрос:
Я написал на Java небольшой алгоритм головоломки N-ферзей (с шахматной доской c * c). Ниже вы найдете код моего рекурсивного метода.
Он не находит все решения.
Что делает моя функция
Идея состоит в том, чтобы сделать в основном методе первый вызов моей функции, предоставляя ей максимальное количество ферзей, пока не будет найдено решение, шахматная доска без ферзя и координаты этих новых ферзей: x = 0, y = 0.
Функция будет проходить через шахматную доску. Для каждого квадрата проверяется, может ли быть помещен ферзь (0; 0) (т. е. : нет угрозы). Ферзь (0;0) может быть размещен? Что ж, мы делаем это (модифицируем шахматную доску) и вызываем функцию (рекурсивный вызов). Этот рекурсивный вызов выполняется с помощью: «максимальное количество ферзей — 1», модифицированной шахматной доски и «y 1 нового ферзя» (немного сложнее).
Найдено решение с n = 4 и c = 4 (обычно есть два решения … !)
amp;amp; Qamp;
Qamp;amp;amp;
amp;amp;amp; Q
amp; Qamp;amp;
Недавний код моей функции
private static void setQueen(int nb_queens, ArrayList<ArrayList<Boolean>> chessboard, int x, int y, ArrayList<ArrayList<ArrayList<Boolean>>> solutions) {
if (nb_queens == 0) { // If there isn't any queen remaining, it means we found a solution
drawChessboard(chessboard);
solutions.add(chessboard);
}
for(int i = x; i < chessboard.size(); i ) {
for (int z = y; z < chessboard.get(i).size(); z ) {
if(!canBePlaced(i, z, chessboard)) {
chessboard.get(z).set(i, true); // On peut donc placer cette reine(x;y) et on le fait
setQueen(nb_queens-1, chessboard, i 1, 0, solutions);
chessboard.get(z).set(i, false);
}
}
}
}
Более старый код
private static void setQueen(int nb_queens, ArrayList<ArrayList<Boolean>> chessboard, int x, int y, ArrayList<ArrayList<ArrayList<Boolean>>> solutions) {
if (nb_queens == 0) {
drawChessboard(chessboard); // Il n'y a plus de reine à placer => on dessine cette solution
solutions.add(chessboard);
}
for(int i = x; i < chessboard.size(); i ) {
for (int z = y; z < chessboard.get(i).size(); z ) {
if(!isAQueenAlreadyPresent(i, z, chessboard)) {
chessboard.get(z).set(i, true); // On peut donc placer cette reine(x;y) et on le fait
setQueen(nb_queens-1, chessboard, i, (z 1 >= WIDTH) ? 0 : z 1, solutions);
chessboard.get(z).set(i, false);
}
}
}
}
Комментарии:
1. Находит ли он какие-либо решения вообще? что вы получаете в результате ? Кроме того, поместите
isAQueenAlreadyPresent(i, z, chessboard)
, это не должно быть проблематично, но кто знает. Кроме того, использование как рекурсии, так и итерации на самом деле бесполезно…2. Я отредактировал OP для отображения результатов 🙂
3. Ах да, теперь я понимаю, почему рекурсия и итерация, конечно. Но, похоже, на самом деле не хватает большого количества результатов, разве их не было бы намного больше? например, симметричное из этих решений? Например, amp;amp;Q amp;amp;amp;amp;Qamp;, который симметричен вашему первому результату.
4. Да, многие решения отсутствуют. Я не понимаю, почему. Я не думаю, что это из-за
isQueenAlreadyPresent
however.5. Не могли бы вы добавить код этой функции?
Ответ №1:
Ах да, это потому, что то, как вы вызываете рекурсивно, ваше дело setQueen(nb_queens-1, chessboard, i, z 1, solutions);
. z 1
Часть — это проблема, она всегда найдет решение справа от первого ферзя, которого вы разместили на глобальной доске.
Редактировать: ах, вы нашли это раньше, приятно.
Итак, проблема в том, что цикл for действует как an if(z>=y)
, потому что он начинается с y
. Это нормально, когда i = x
(чтение первой строки), но не когда i > x
. Итак, простое решение — поместить y = ( i == x ) ? y : 0
сразу после первого for
цикла.
Есть еще более чистое решение, например, использование одного индекса для обхода всей шахматной доски.
Я также предлагаю вам переименовать ваш параметр в startX и startY (вместо x и y вы можете использовать x и y в цикле, чтобы быть более понятными).
Редактирование 2: из-за правил игр в одной строке никогда не будет ферзя, поэтому подразделение может выполнить рекурсивный вызов like setQueen(nb_queens-1, chessboard, i 1, 0, solutions);
( i 1
потому что вы начинаете непосредственно со следующей строки). Из-за этого вы даже можете удалить int y
параметр из setQueen
метода и всегда запускать z loop
с 0.
Комментарии:
1. Если я напишу:
int new_z = (z 1 >= WIDTH) ? 0 : z 1;
, а затем выполню рекурсивный вызов сnew_z
помощью (и неz
), кажется, что некоторые решения все еще отсутствуют с n = 4 и c = 4 . Я должен найти 2 решения, и у меня есть только одно. Вы знаете, почему?2. Вы могли бы легко устранить проблему, выполнив
for(int i = 0; ..
иfor (int z = 0;..
что вы довольно уродливы и имеете сложность n ^ 3. (написание лучшего решения)3. Так ты думаешь, я не могу сохранить свои
i,z = a_parameter
дваfor
?4. Да, вы можете, но для этого требуется другое решение, которое я написал в редактировании.
5. Я отредактировал свой OP (чтобы показать новый код). Могу ли я указать ваш логин, потому что вы мне помогли? Мои изменения: «i 1, 0» в рекурсивном вызове, И я удалил
y = ( i == x ) ? y : 0
.