Подтвердить что ты не робот

Расстояние Манхэттена превышает оценку и делает меня сумасшедшим

Я реализую алгоритм a-star с Манхэттенским расстоянием, чтобы решить 8-головоломка (в C). Кажется, что он работает очень хорошо и проходит множество модульных тестов, но он не может найти кратчайший путь в одном случае (он находит 27 шагов вместо 25).

Когда я изменяю эвристическую функцию на расстояние Хэмминга, она находит в 25 шагах. Также находит в 25 шагов, когда я делаю функцию расстояния Манхэттена, чтобы вернуть половину фактической стоимости.

Вот почему я считаю, что проблема лежит где-то в функции расстояния Манхэттена, и это связано с оценкой стоимости (следовательно, недопустимой). Я подумал, что, возможно, что-то не так происходит в программе C, поэтому я написал небольшой Python script для проверки и проверки вывода функции расстояния Манхэттена, и оба они дают точный результат.

Я действительно смущен, потому что эвристическая функция, кажется, единственная точка отказа, и она кажется правильной в то же время.

8-puzzle start goal

Вы можете попробовать этот решатель и поставить порядок черепицы как "2,6,1,0,7, 8,3,5,4" Выберите алгоритм Манхэттенского расстояния, и он найдет его в 25 шагов. Теперь измените его на расстояние Манхэттена + линейный конфликт, и он найдет 27 шагов.

Но мое расстояние Манхэттена (без линейного конфликта) находится на 27 ступенях.

Вот мой общий алгоритм:

manhattan_distance = 0
iterate over all tiles
if the tile is not the blank tile:
find the coordinates of this tile on the goal board
manhattan_distance += abs(x - goal_x) + abs(y - goal_y)

Я думаю, что если с какой-то важной частью было что-то очень плохое, он не прошел бы все 25+ предыдущих тестов, так что это может быть какой-то краевой случай.

Здесь прокомментирована функция расстояния Манхэттена в C:

int ManhattanDistance(Puzzle p, State b){
   State goal = getFinalState(p);
   int size = getSize(b);
   int distance = 0;
   if (getSize(goal) == size){ // both states are the same size
      int i, j;
      for(i=0; i<size; i++){
         for(j=0; j<size; j++){ // iterate over all tiles
            int a = getStateValue(b, i, j); // what is the number on this tile?
            if (a != 'B'){ // if it not the blank tile
               int final_cordinates[2];
               getTileCoords(goal, a, final_cordinates); // find the coordinates on the other board
               int final_i = final_cordinates[0];
               int final_j = final_cordinates[1];
               distance +=  abs(i - final_i) + abs(j - final_j);
            }
         }
      }
   }
   return distance;
}

Пожалуйста, помогите мне.

РЕДАКТИРОВАТЬ: Как уже говорилось в комментариях, код, предлагаемый для открытия узлов, можно найти здесь

4b9b3361

Ответ 1

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

При чтении кода, который вы предоставили [в комментариях], я думаю, что я понял, где проблема лежит в строке 20:

if(getG(current) + 1 < getG(children[i])){

Это неправильно! Вы проверяете, есть ли g(current) + 1 < g(children[i]), вы действительно хотите проверить: f(current) + 1 + h(children[i]) < g(children[i]), так как вы хотите проверить это значение с помощью эвристической функции children[i], а не current!
Обратите внимание, что оно идентично, чтобы установить f(children[i]) = min{f(children[i]),f(current)+1}, а затем добавив h(children[i]), чтобы получить значение g.