Найдите кратчайший путь с наименьшим возможным количеством ребер вокруг препятствия

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

Путь должен быть рассчитан таким образом, чтобы обходить препятствия определенной формы (чаще всего круглой или прямоугольной).

Информация, в которой хранится путь, должна быть либо декартовыми координатами путевых точек пути, либо, альтернативно, полярными координатами (то есть командами для выполнения моего устройства, такими как поворот на угол альфа, перемещение на расстояние b). Однако я бы предпочел декартовы координаты каждой путевой точки.

Там нет навигационной сети или чего-то еще, только система координат и информация о том, где находятся препятствия и другие запретные зоны, из которых некоторые фиксируются, а некоторые могут (и вполне вероятно, будут) двигаться.

Ах, и все это должно быть как-то доступно в .NET.

Спасибо

// редактировать: чтобы немного прояснить ситуацию, вот изображение того, что я собираюсь сделать: https://dl.dropbox.com/u/8802336/path.png


person Hendrik Wiese    schedule 13.03.2013    source источник
comment
Неясно, с чем у вас проблема - не работает ли A* или обычный метод Дейкстры поиск пути для Вы? Особые причины/проблемы/ограничения?   -  person Alexei Levenkov    schedule 14.03.2013
comment
См. stackoverflow.com /вопросы/5303538/   -  person Mihai8    schedule 14.03.2013
comment
Я предполагаю, что мне понадобятся некоторые изображения, чтобы объяснить мою проблему... просто дайте мне секунду, чтобы придумать их.   -  person Hendrik Wiese    schedule 14.03.2013
comment
Ваш вопрос недостаточно полный - НАСКОЛЬКО дорого сделать новое преимущество по сравнению с сокращением пути? Должен ли я оптимизировать для наименьшего возможного количества ребер (например, вокруг круга я бы сделал большой L-образный путь) или есть компромиссы?   -  person Patashu    schedule 14.03.2013
comment
Хорошо. Для каждого нового ребра мне нужно останавливать устройство, поворачивать его в направлении следующего ребра и снова ускорять его. Это отнимает время. Поэтому мне нужно свести к минимуму количество остановок, поворотов, ускорений. Я добавлю изображение того, что мне нужно, к моему вопросу через секунду ...   -  person Hendrik Wiese    schedule 14.03.2013


Ответы (2)


Ваш вопрос можно интерпретировать двояко.


<сильный>1. Я хочу найти кратчайший путь, разрывая нити, выбирая путь(и) с наименьшим количеством ребер

Вы можете сделать это, добавив небольшое число ε к весу каждого ребра графа. Число должно удовлетворять ε < 1/numberOfEdges. Это увеличит длину каждого пути на ребра * ε, что означает, что более короткие пути будут предпочтительнее. Это работает даже с ребрами отрицательного веса. Будьте осторожны с неточностями с плавающей запятой.


<сильный>2. Я хочу найти путь с наименьшим количеством поворотов, разбивая ничьи, выбирая тот или иные пути с кратчайшим путем

Вы можете сделать это, добавив некоторое большое число E к весу каждого ребра на графе. Число должно удовлетворять E > sumOfAllEdgeWeights. Это гарантирует, что будут рассматриваться только пути с наименьшим возможным числом ребер. Это не работает с ребрами с отрицательным весом. Будьте осторожны с целочисленными переполнениями.

person BlueRaja - Danny Pflughoeft    schedule 13.03.2013
comment
Номер 2 - хорошее решение - просто A *, и сделать так, чтобы изменение направления стоило большой суммы (и большая сумма может меняться в зависимости от вращения, того, как долго вы ускорялись и так далее). Однако это даст только 8-стороннее движение. - person Patashu; 14.03.2013
comment
Это 8-стороннее движение и его точность в отношении точного пути краев, к сожалению, делают A * неприменимым. Мне нужны только углы пути, путевые точки. Информация о ребрах не требуется. - person Hendrik Wiese; 14.03.2013
comment
@SeveQ: Судя по вашему изображению, кажется, что вы действительно ищете алгоритм под любым углом. См. здесь . - person BlueRaja - Danny Pflughoeft; 14.03.2013
comment
@ BlueRaja-DannyPflughoeft, это выглядит многообещающе. Я посмотрю на это. - person Hendrik Wiese; 14.03.2013
comment
@BlueRaja - Дэнни Пфлугхофт, я читаю это, и мне это нравится :) - person Patashu; 14.03.2013

Если цель:

1) Минимизируйте количество ребер.

2) Минимизируйте расстояние.

В этом порядке вы можете попробовать следующее:

1) Проведите линию от начала до конца.

2) Рассчитайте каждый объект, с которым сталкивается ваша линия.

3) Для каждого из этих объектов вычислите обе точки, перпендикулярные объекту, которые позволят вам разделить путь на два сегмента пути. Вы можете сделать это для прямоугольников, разделив линию на два сегмента: для сегмента A посмотрите, через какой из четырех углов он может пройти, для сегмента B посмотрите, через какой из четырех углов он может пройти, и попробуйте все комбинации, пока не найдете два, которые дают наименьшее смещение. Для кругов я забыл, как это сделать, но есть только одно решение с обеих сторон, где два сегмента пути находятся на одном уровне с кругом, поэтому вы можете сделать это с помощью тригонометрии или чего-то еще (я попытаюсь понять это :))

Для обоих новых путей вызовите 4) в режиме рекурсивного ветвления.

4) Для обоих сгенерированных сегментов линии повторяйте расчет до тех пор, пока не останется столкновений. Как и в случае с A*, вы должны сначала вычислить пути, которые кажутся лучшими (с наименьшим количеством оставшихся столкновений, или сначала сделайте самый мелкий путь, если это слишком сложно).

5) Выберите лучший путь с помощью любой метрики, которую вы хотите. В стиле A* вы должны отсортировать свой список так, чтобы путь, который является лучшим с точки зрения вашей метрики, был наверху, и чтобы вы могли просто выбрать первый путь для завершения.

Я не могу доказать в своей голове, что это всегда будет работать, но я видел что-то подобное раньше.

РЕДАКТИРОВАТЬ

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

-Сторона A: идет от начала линии (или конца линии) xs,ys до центра круга xc,yc, длина = a

-Сторона B: идет от центра xc,yc куда-то по окружности, поэтому длина = r

-Сторона C: идет от конечной точки стороны B до xs,ys (гипотенуза)

Угол, образованный A и B, является прямым углом, и мы знаем длину A и B, поэтому мы можем вычислить длину C как sqrt (A ^ 2 + B ^ 2)

Наконец, мы знаем, что длина C = длина / грех (угол (от B до C)) = длина / грех B (угол (от A до C)), что означает, что мы можем выполнить тригонометрию, чтобы найти угол от A до C и угол B к С.

Это позволяет нам полностью построить одну сторону сегмента пути. Повторите для другой стороны, и у нас есть путь, разделенный на две части, который находится на одном уровне с кругом на обоих сегментах -> минимизирует добавленное расстояние.

person Patashu    schedule 13.03.2013
comment
Хорошо, мне нужно пройти через это несколько раз, чтобы понять это. По крайней мере, я могу подтвердить, что порядок правильный: сначала минимизировать количество ребер, затем минимизировать расстояние. Наша главная проблема — ускорение. Скорость не такая уж большая проблема. Таким образом, ребра действительно стоят больше, чем расстояние. - person Hendrik Wiese; 14.03.2013