#algorithm #graph #dynamic-programming #greedy
#алгоритм #График #динамическое программирование #жадный
Вопрос:
Существуют платформы, которые могут быть размещены на разных высотах. Например, эта карта показывает, как были размещены платформы (в программе она представлена в виде матрицы NxM, |N|, |M| <= 100
_ _ _
D _ _ _
_ _
_
S _ _ _ _ _
На этой карте space
означает space
, _
— платформа, S
— платформа, с которой мы начинаем, D
— пункт назначения. Монстр, который ходит по этой карте, может прыгать вверх, вниз или перемещаться влево или вправо.
Возможный способ добраться D
от S
монстра:
D
S
или он может достичь D
таким образом:
_ _ _
D _ _ _
_ _
_
S _ _ _ _ _
Итак, комбинации достижения точки назначения могут варьироваться многими способами, но главное в том, что в первом случае максимальное расстояние прыжка, которое совершает монстр, равно 1
, потому что максимальное расстояние между двумя платформами таким образом равно 1
. Во втором случае монстр достиг цели очень быстро, но он совершил прыжок на расстояние 2
. Основная цель монстра — добраться до точки назначения и не совершать больших прыжков (как можно меньше), и из-за этого предпочтителен первый способ. Вопрос в том, какой алгоритм я должен использовать, чтобы найти такой способ, при котором максимальное расстояние перехода было бы минимальным?
Я подумал о двух способах:
- Перебор, но это будет неудобно, когда количество платформ будет
=N*M
; - Каким-то образом перенесите эту матрицу в граф, где каждая платформа представлена как узел графа, а ребра представлены расстояниями переходов, и найдите минимальное связующее дерево, но, во-первых, я не знаю, как создать матрицу смежных таким образом, и это будет правильно.
Ответ №1:
Для анализа карты и поиска узлов:
for i from 1 to N
for j from 1 to M
if map(i, j) == 'S'
nodes.add(i, j);
start = nodes.Count;
elseif map(i, j) == 'D'
nodes.add(i, j);
dest = nodes.Count;
elseif map(i, j) == '_'
nodes.add(i, j);
end
end
end
В приведенном выше псевдокоде я предполагаю, что nodes.add(i, j)
добавляет новый узел с node.x = 1
и node.y = j
в список узлов.
Затем построить матрицу смежности:
n = nodes.Count;
adj = n by n matrix, filled with inf;
for i from 1 to n
for j from i 1 to n
if (nodes[i].x == nodes[j].x) || (nodes[i].y == nodes[j].y)
adj(i, j) = abs(nodes[i].x - nodes[j].x)
abs(nodes[i].y - nodes[j].y);
end
end
end
Остальное — проблема кратчайшего пути. Используйте алгоритм Дейкстры, чтобы найти кратчайший путь между start
dest
узлами и.
Комментарии:
1. Мне не нужно находить кратчайший путь! Мне нужно найти путь, содержащий минимальные ребра!
2. @AyratArifullin Конечно, но алгоритм тот же. При увеличении пути и обновлении текущего кратчайшего пути вам не нужно сравнивать
sum(weights)
, ноmax(weights)
.3. @AyratArifullin Кроме того, что, если бы было несколько путей с одинаковым значением самого длинного перехода? Разве вы не хотите вернуть кратчайший? Или, может быть, тот, у которого наименьшее количество переходов с максимальной длиной. Все они используют один и тот же алгоритм, но с разными способами сравнения двух путей.
4. @AyratArifullin Имейте в виду, что Дейкстра на самом деле является алгоритмом оптимизации и пытается минимизировать «стоимость», а «длина» исходит только из терминологии хорошо известной проблемы «Проблема кратчайшего пути». Теперь, когда «стоимость» в вашей задаче является «самым длинным скачком», просто используйте свою собственную стоимость в том же алгоритме.
5. Я немного исправил ваше предложение и принял решение. Вы можете проверить это ниже. Спасибо, что поддержали мою идею! Вы только что подтолкнули меня дальше
Ответ №2:
Благодаря сообщению выше, я решил закончить идею и получил этот код, и для тестовых случаев, которые мне дали, он работает нормально. Итак, идея такова:
- Из заданной карты платформ необходимо создать граф, в котором один узел представляет одну платформу (включая начальную и конечную платформы), а ребра между узлами представлены как расстояние между ними;
- Когда вы сформировали график, ваша цель — найти минимальное связующее дерево и найти максимальный вес ребра в этом дереве — это ответ. Код очень большой, и, пожалуйста, проверьте его на моем github! Обратите внимание, что
1
означает платформу,2
означает начало и3
является пунктом назначения: