Реализация возврата в Knight's tour с выбором массива шагов

0

Поэтому я придумал эту реализацию для решения тура рыцарей для шахматной доски 8 * 8. Но похоже, что он занимает много времени (так долго, что я должен его остановить). Но если я заменил dx, dy-массивы на один, написанный в комментариях, и программа работает как магия и дает результат. Говорят, что он умело выбирает массив, так что агенту bruteforce повезло быстро найти решение.

Но как же придумать этот массив на первом месте, этот массив (dx, dy) я получил от какого-то другого кода. Так может ли кто-нибудь объяснить мне, почему этот код работает с этими массивами (в комментарии), а не с моим.

#include <cstdio>

using namespace std;

int dx[8] = {  1,  1, 2,  2,  -1, -1, -2, -2};
int dy[8] = {  2, -2, 1, -1,  2,  -2,  1, -1};

//int dx[8] = {  2, 1, -1, -2, -2, -1,  1,  2 };
//int dy[8] = {  1, 2,  2,  1, -1, -2, -2, -1 };

bool solve(bool arr[8][8],int x,int y,int moves){
    if(moves==0)return true;
    if(x<0 || y<0 || x>7 || y>7 || arr[x][y])return false;
    arr[x][y]=1;

    for(int i=0;i<8;i++)
        if(solve(arr,x+dx[i],y+dy[i],moves-1)){
            printf(" (%d,%d) ",x,y);
            return 1;
        }
    arr[x][y]=0;
    return false;
}

int main()
{
    bool arr[8][8];
    for(int i=0;i<8;i++)    for(int j=0;j<8;j++)    arr[i][j]=0;
    solve(arr,0,0,64);
    puts("");
}
  • 0
    Мой совет - пройтись по коду с помощью отладчика, отслеживая значения переменных.
  • 0
    Кто они" ?
Показать ещё 3 комментария
Теги:
algorithm
backtracking
hamiltonian-cycle

2 ответа

1
Лучший ответ

Резюме

Причина, по которой закомментированный массив dx/dy работает лучше, чем ваш начальный массив, заключается в том, что он выполняет поиск по глубине для решения в другом порядке - порядок, выбранный с учетом конкретного решения и который поэтому способен найти это решение относительно быстро.

Детали

Поиск по глубине начинается с корня дерева и проверяет каждый путь к листу. Например, поиск в глубину этого дерева сначала рассмотрим путь, который посещает только a узлы (a → a → a), то он будет возвращаться назад немного и исследовать a → a → b, то a → a → c и т.д.

Изображение 174551

Это может занять много времени, если дерево велико и нет решений, которые начинаются с посещения a, потому что вам приходится тратить много времени на изучение всех путей, начинающихся с a прежде чем вы сможете перейти к лучшим путям.

Если вам известно, что есть хорошее решение, начинающееся с d, вы можете немного ускорить процесс, переупорядочив узлы вашего дерева, чтобы начать с изучения путей, начинающихся с d:

Изображение 174551

С самого начала вы удалили 7/8th работы, которую должна выполнить ваша программа, потому что вам никогда не придется искать пути, начинающиеся с чего-то другого, кроме d ! Выбирая хороший порядок для остальных узлов, вы можете получить аналогичные ускорения.

Вы можете видеть, что это происходит, если вы посмотрите на результаты своей программы:

(0,7)  (1,5)  (3,4)  (1,3)  (0,1)  (2,0)  (4,1)  (6,0)  (7,2)  (5,3)  (7,4)
(6,2)  (7,0)  (5,1)  (4,3)  (3,1)  (5,0)  (7,1)  (5,2)  (7,3)  (6,1)  (4,0)
(3,2)  (4,4)  (2,3)  (0,2)  (1,0)  (2,2)  (3,0)  (1,1)  (0,3)  (2,4)  (1,2)
(0,4)  (1,6)  (3,7)  (2,5)  (3,3)  (5,4)  (6,6)  (4,5)  (6,4)  (7,6)  (5,5)
(4,7)  (2,6)  (0,5)  (1,7)  (3,6)  (5,7)  (6,5)  (7,7)  (5,6)  (3,5)  (1,4)
(0,6)  (2,7)  (4,6)  (6,7)  (7,5)  (6,3)  (4,2)  (2,1)  (0,0)

Первый шаг (чтение снизу) - от (0,0) до (2,1), что соответствует dx=2 и dy=1 - и, конечно, в прокомментированном списке dx/dy, что первая возможность, которая рассматривается. На самом деле, первые три шага этого решения используют dx=2 и dy=1, что фактически означает, что вам нужно искать только крошечное небольшое дерево, а не целое.

  • 0
    Проблема на самом деле симметрична и имеет несколько решений. Таким образом, для решения, которое начинается с dx = 2 и dy = 1, будет другое решение, которое начинается с dx = 1 и dy = 2 (которые являются первыми значениями, используемыми в незакомментированном коде). Я думаю, что улучшение связано больше со вторым элементом в списке и его отношением к первому элементу.
  • 0
    Конечно, это честно. Я предполагаю, что упорядочение дельт - особенно первых нескольких - это эвристика, которую можно настроить, чтобы быстро найти конкретное решение.
0

В шахматах есть восемь действительных рыцарских ходов:

Изображение 174551

Два массива перечисляют эти восемь ходов.

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

Это все, что есть.

  • 0
    чувак, ты не ответил на мой вопрос, почему это происходит, с этим массивом, я также пробовал некоторые другие комбинации, но они не работали
  • 0
    @Jignesh: Не нужно быть грубым, особенно по отношению к тем, кто пытается вам помочь.
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню