![]() |
Минимальные пути в графах - нид хелп!
Собственно возник вопрос, не знает ли кто быстрого алгоритма нахождения минимального пути между двумя вершинами в графе?
Использовал Дейкстру - слишком долго работает, граф довольно большой, думаю будет больше 1000 вершин... (30 сек на П-4 1600!!!) Видел быструю реализацию подобной задачи на http://ati.su/tc.php - вот и интересует практически та же задача. Кто подскажет? |
а сколько сторон? что-то слишком долго, Дейкстра работает O(logV(V+E))
|
to AleXXXSoft
А по подробнее о графе и весах сказать можешь? Дело в том, как я знаю, алгоритм Дейкстры довольно эффективный алгоритм для нахождения кратчайшего пути с положительными весами (если веса не обязательно положительные, то алгоритмы предлагаемые в книгах ещё более медленные). Поэтому я считаю, что чтобы постоить более "шустрый" алгоритм нужно учитывать специфику задачи. З.Ы. Возможно структуры данных выбраны не оптимальным образом для реализации алгоритма Дейкстры. Можешь попробовать реализовать алгоритм Дейкстры с использованием бинарных куч, а лучше с использованием куч Фибаначи. З.З.Ы Имхо нам будет проще если увидим листинг проги и исходные данные. |
Попробуй алгоритмы Флойда - иногда они быстрее чем а. Дейкстры.
http://www-unix.mcs.anl.gov/dbpp/text/node35.html |
Цитата:
P.S. Дейкстра, насколько я знаю, по времени O(n^3) Цитата:
|
спробовал Флойда. В общем он же рассчитывает кратчайшие пути от всех ко всем, работает по времени дольше Дейкстра от одного к одному. Модифицировал Флойда, чтобы считать от одного ко всем... стал работать раз в 10 быстрее (т.е. как и Дейкстра), но! самого главного-то нет! минимальную длину маршрута я знаю, но пути нет :(
Цитата:
буду пробовать реализовать бинарную кучу самостоятельно |
Вложений: 2
сделал нечто с помощью бинарной кучи для 1000 вершин, между 50% всех вершин есть связи, получил ускорение на 10 сек в лучшем случае и замедление почти в 2 раза в худшем случае... выкладываю исходники, может кто что подскажет...
жрёт памяти немерено! не знаю, что и делать, в реальной дорожной сети будет больше 14 тысяч городов! Хотя дорог много меньше... road.php - собственно программа heap.php - функции для кучек |
AleXXXSoft:
В случае с картой России, обобщенный алгоритм Дейкстры ОЧЕНЬ не оптимален. Россия (как и любая страна) со всеми ее дорогами - это очень специфичный граф. Ищи не алгоритм поиска кратчайшего пути в графе, а алгоритм поиска кратчайшего пути на плоскости. |
Цитата:
|
to AleXXXSoft
Я php не знаю, так что если что я не понял необижайтесь. Как я понял в проге считается, что граф полный. Для карты России это будет явно не так. Поэтому предлагаю улучшение программы: 1) Граф хранить не с помощью матрицы инциденции, а с помощью двух массивов. Пусть A,B массивы рёбер ({A[ i ],B[ i ]} - ребра i=1,|U| U-множество ориентированных дуг). Т.е. ты каждое ребро заменяешь на две дуги. Сортируешь массивы А и B по значениям массива A. (т.е. теперь {A[ i ],B[ i ]} - ребра, и A[1]<=A[2]<=...<=A[|U|]). Потом вводишь новый массив F размера |I|+1 , где F[ i ]=min{j:i<=A[j]} например с помощью цикла: Цитата:
2) Насчёт куч скажу немного попозже, там вроде процедуру "подъёма" нужно огранизовать. _________________________________ Продолжение: Блин мною была допущена ошибка в куске программы. Цитата:
Вы при нахождении возможности уменьшения расстояния (т.е. если "$l[$v]+$d[$v][$k]<$l[$k]). Забравываете элемент в кучу, при этом "старый" элемент остаётся. Оттого куча зря растёт и рассматривается одна и та же вершина по несколько раз (лишняя трата времени). Нужно, Имхо, делать следующим образом: 1) Если текущее значения расстояние до данной верщины бесконечность ( if $l[$v]==BIG), то уменьшаем это и запихиваем в кучу. 2) если нет, то уменьшаем значение данной вершины и продвигаем вверг в куче (если меньше предка, то делаем обмен и т.д.). При этом встаёт вопрос, где находится элемент $l[$v] в куче, который решается введением вспомогательного массива position (position[v] - индекс элемента к куче). И теперь при всех операциях нужно следить за position, но это добавляет одну операцию, что не увеличивает асимтотическую сложность. |
тыкс, ну насчет хранения данных - это да, много и не экономно, переделаю... но сперва бы разобраться со скоростью.
Кстати с вашей предложенной моделью хранения будет лучше, т.к. данные лежат в базе, сразу могу и достать их сортированными. насчет куч, теперь вижу свою ошибку, но нигде не могу найти алгоритм обновления элемента в куче... ну или удаления... не поможете? |
Цитата:
|
Цитата:
1) Произвести их слияние. (как итерация в merge-sort) 2) Хранить четыре массива B1,F1,B2,F2. Имхо, первый вариант лучше. Цитата:
З.Ы. Как я писал с php я не встречался (этот случай не всчёт :) ). Оттого буду презнателен, если расскажете как называется и где найти интерпретатор для php и что-то вроде отладчика. Тогда, возможно, моя помощь будет существенней. З.Ы.Ы Цитата:
Алгоритм подъёма (именно то, что Вам нужно) Вы же почти реализовали: при вставке элемента в кучу, Вы же сначала добавляете элемент в конец кучи, а потом осуществяете его подъём (в Вашем же исходнике так написано). Алгоритм удаления: Уменьшаем ключ до минус бесконечности, осуществяем подъём и удаление минимального. Это так навскидку, но, думаю, можно что-нибудь пооптимальнее придумать (например, ставить последний элемент кучи на место удаляемого, а потом производить или подъём, или спуск. З.З.З.Ы. В моём предыдущем посте надоело исправлять не точности. Здесь [i] воспринимается не как индекс массива, а как курсив. На всякий, случай имейте ввиду и не кидайте гнилыми помидорами :)) . |
Вложений: 2
исходники вложил, массивы пока не переделывал, собственно разбирался с кучей....
ковырялся с функциями кучи просто небольшими массивчиками - вроде они работают правильно (если, я, конечно, правильно понял алгоритмы из книжки, которые я там и реализовал) насчет PHP - там все не так просто, по крайней мере дистрибутив ПХП можно найти тут: http://php.net/ - 5-ю версию не брать, использовать нужно CLI-версию отладчиков для ПХП не встречал сам.... пользуюсь, блин, банальными print_r - распечатка переменных.... в принципе мне бы подошел готовый алгоритм на Перле или Си, он у меня даже есть реализован, но так как там повсеместно используются списки и прочие хитрости языков, я там вообще не допираю... в ПХП, увы, этого ничего нет, все делается "в тупую"... :idontnow: потому все готовые алгоритмы не катят... Цитата:
|
Цитата:
По теме: Учитывая что сама структура не сильно динамическая (дороги у нас пока не воруют :) ), то можно попробовать найти все пути пути и записать их в таблицу, из которой потом выбирать будет много быстрее, чем искать заново. |
Цитата:
Насчет заранее сделанных расчетов, я уже думал об этом... 14 тысяч точек - города, хрен знает сколько ребер, нужно учесть все возможные пути от точки к точке - табличка будет ЧЕРЕЗЧУР великовата. Была мысль, и она еще жива, неким образом кешировать уже вычисленные пути. А вот если считать все сразу - никаких ресурсов не хватит.... один путь моим алгоритмом считается по 20-30 сек.... собственно потому и зашел разговор о более быстром алгоритме. |
to AleXXXSoft
А Вы на правильность (не только на скорость) программу проверяли. Имхо когда запихиваешь элемент в кучу нужно писать не $r["data"]=$v; а $r["data"]=$k; |
Цитата:
хотя нет, считает, но долго. ОЧЕНЬ. дольше чем методом в лоб... думаю что-то с алгоритмами и функциями кучи неправильно, кушает память снова... |
Вложений: 2
Ну вот немного поправил. Работает сек. 6-8. На правильность не тестировал, на прожорливость к памяти тоже.
З.Ы. Нек. "новые", написанные Вами я не читал даже (извиняйте). Кажется, они даже не нужны. _______________________ Добавлено: Присоединяю немного поправленную версию. При исполнении кот. видно, что основную часть времени отжирает генерация матрицы (24.3 против 6.43 после увеличения размера). Память отжирается на этапе генерации матрицы. Имхо это достойный задел, т.к. прога оперировака с 1500^2=2 250 000 рёбрами, а в реальной задаче дуг бедет 14 000*A, где A - среднее количество исходяцих рёбер из вершины (Имхо A<=20). {Здесь, я считаю, что будет применено, написанное мною улучшение связанное со способом хранения графа} З.Ы. Чтобы узнать, что я поправил, достаточно воспользоваться прогами fc для dos\win и diff для unix (Ex. "fc /l <file1> <file2> >> <result>, результат сраврения будет в <result>) З.З.Ы за правильность работы не отвечаю. З.З.З.Ы. Цитата:
|
Оценка взялась из Кормена. Кроме того тут об етом говоритса:
http://algolist.manual.ru/forum/show...2840/Main/2679 Недеюсь поможет, хотя немного поздно :молись: |
to Drakosha
Только сейчас заметил: Вы наверное имели ввиду O(log(V)*(V+E)), а не O(log(V(V+E)), как я сначала подумал. :beer: Цитата:
|
миллон извинений, буду ставить больше скобок. Мне почему-то было понятно "O(logV(V+E))"
|
2 skiproff
спасибо, буду ковырять P.S. память жрет)) ой жрет)) |
Цитата:
Цитата:
Если Вы представите граф двумя массивами, то памяти на это будет уходить |I|+2*|U|. Если предположить, что среднее число исходящих рёбер их вершины будет A. (Имхо A<=20 в Вашей задаче), то памяти будет ухощить на (A+1)*|I|=(A+1)*14 000 << 1500*1500 = 2 250 000. (Чтобы удостовериться, что память отжирается на этапе генерации матрицы, запустите диспетчер задач и сразу станет видно, что после того как появляется сообщение, что граф сгенеген (вываливается первое сообщение) память перестаёт "расходоваться". Цитата:
|
ковырять - это значит продолжать работу над задачей, как сделаю все - покажу :)
насчет графа и памяти, я понял |
| Часовой пояс GMT +4, время: 01:06. |
Powered by vBulletin® Version 3.8.5
Copyright ©2000 - 2026, Jelsoft Enterprises Ltd.