Я реализую алгоритм a-star с Расстояние Манхэттена для решения 8-головоломки (на языке C). Кажется, он работает очень хорошо и проходит множество модульных тестов, но не может найти кратчайший путь в одном случае (он находит 27 шагов вместо 25).
Когда я изменяю эвристическую функцию на Расстояние Хэмминга , она находит за 25 шагов. Также находит за 25 шагов, когда я делаю функцию расстояния Манхэттена, чтобы возвращать значение половину фактических затрат.
Вот почему я считаю, что проблема заключается где-то в функции расстояния Манхэттена, и она заключается в завышенной оценке стоимости (следовательно, недопустима). Я подумал, что, может быть, что-то еще не так в программе на C, поэтому я написал немного Сценарий Python для тестирования и проверки вывода только функции расстояния Манхэттена, и они обе дают один и тот же результат.
Я действительно сбит с толку, потому что h евристическая функция кажется единственной точкой отказа, и в то же время она кажется правильной.
Вы можете попробовать этот решатель и установить порядок фрагментов вроде «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
Пожалуйста, помогите мне.
РЕДАКТИРОВАТЬ: Как обсуждалось в комментариях, код, предоставленный для открытия узлов, можно найти здесь
Проблема, кажется, не в вашей эвристической функции, а в самом алгоритме. Из вашего описания проблемы и того факта, что это происходит только в некоторых конкретных случаях, я считаю, что это связано с повторным открытием замкнутой вершины, когда вы найдете лучший путь к ней.
Читая код, который вы предоставили [в комментариях], я понял, в чем заключается проблема, в строке 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
.