Вы должны понимать, что когда вы пишете
List.map (fun x -> find_shortest_path x m) (find_next_step n))
Вы будете буквально вычислять все «кратчайшие пути отсюда» из всех возможных соседей, а затем вычислять минимум всех этих результатов.
Таким образом, в вашем коде есть бесконечный цикл: если вы начинаете с позиции A
и пытаетесь вычислить кратчайший путь от одного из его соседей B
, то find_shortest_path
, вызванный из B
, неизбежно попытается Посмотрите, как долго будет длиться путь, если его первым ходом будет возврат к A
. Таким образом, среди всех других возможных ходов, которые также будут опробованы, вы вычислите «длину» цикла A-B-A-B-A-B...
, то есть бесконечный цикл.
Есть несколько способов избежать этой проблемы (которая не связана с программированием OCaml как таковым, это ошибка в логике вашей программы, которая будет проявляться на любом языке):
используйте поиск в ширину вместо поиска в глубину, чтобы вы постепенно исследовали все пути заданной длины, останавливаясь на наименьшем выигрышном пути, который вы найдете; если вы хотите, это соответствует параллельному исследованию всех путей, поэтому не проблема иметь бесконечные пути до тех пор, пока вы останавливаетесь (потому что вы нашли другое решение) перед попыткой поиска по всему бесконечному пути
отметьте места, которые вы уже посетили, чтобы не «возвращаться» (это никогда не будет кратчайшим способом добраться до места назначения)
если вы используете поиск в глубину, это деликатно, потому что эти метки должны быть локальными для поиска (вы не можете просто изменить матрицу логических значений); Например, вы можете добавить параметр int list
к вашим find_shortest_path
функциям, который будет списком мест, которые являются частью текущего исследуемого пути; прежде чем пытаться вычислить кратчайший путь из возможных соседей, убедитесь, что его нет в этом списке. Для чего-то более эффективного вы можете использовать набор (module IntSet = Set.Make(struct type t = int let compare = Pervasives.compare)
) (логарифмический, а не линейный, тест членства) или использовать изменяющуюся логическую матрицу, в которой вы осторожны, чтобы отслеживать изменения состояния при выборе другого пути.
если вы используете поиск в ширину, вы можете использовать глобальную логическую матрицу «мест, которые вы уже посетили», потому что вы одновременно исследуете все пути до заданной длины; поэтому, если вы встречаете место, которое уже помечено как посещенное, вы знаете, что другой путь посещал его раньше, так что оно уже впереди вас, и нет смысла пытаться получить от него кратчайший путь.
Итак, краткий ответ: вы должны узнать о поиске в ширину.