Я просмотрел ссылку на алгоритм Дейкстры, которую вы разместили в комментариях, и я считаю, что это источник вашей неэффективности.Внутри внутреннего цикла Дейкстры он использует крайне неоптимизированный подход, чтобы определить, какой узел исследовать следующим (линейное сканирование каждого узла на каждом шаге).Проблемный код в двух местах.Первый - это код, который пытается найти следующий узел для работы:
mini = -1;
for (i = 1; i <= n; ++i)
if (!visited[i] && ((mini == -1) || (d[i] < d[mini])))
mini = i;
Поскольку этот код вложен в цикл, который посещает каждый узел, сложность (как упомянуто в ссылке)O (| V | 2 ), где | V |это количество узлов.В вашем случае, так как | V |составляет 30000, будет девятьсот миллионов итераций этого цикла в целом.Это мучительно медленно (как вы уже видели), но нет необходимости делать такую большую работу.
Здесь есть еще одна проблема, которая пытается найти, какое ребро на графике следует использовать для уменьшениястоимость других узлов:
for (i = 1; i <= n; ++i)
if (dist[mini][i])
if (d[mini] + dist[mini][i] < d[i])
d[i] = d[mini] + dist[mini][i];
Это сканирует всю строку в матрице смежности в поисках узлов для рассмотрения, что занимает время O (n) независимо от того, сколько исходящих ребер покидает узел.
Хотя вы можете попытаться исправить эту версию Dijkstra в более оптимизированной реализации, я думаю, что правильный вариант здесь - просто выбросить этот код и найти лучшую реализацию алгоритма Dijkstra.Например, если вы используете псевдокод из статьи Википедии , реализованный с помощью двоичной кучи , вы можете получить алгоритм Дейкстры, работающий в O (| E | log | V |).В вашем случае это значение составляет чуть более двух миллионов, что примерно в 450 раз быстрее, чем ваш текущий подход.Это огромная разница, и я готов поспорить, что с лучшей реализацией Dijkstra вы в конечном итоге получите код, выполняющийся за значительно более короткое время, чем раньше.
Кроме того, вы можете захотетьрассмотрим параллельное выполнение всех поисков Дейкстры, как отметил Джейкоб Эггерс.Эта камера дает вам дополнительное ускорение для каждого процессора, который у вас есть.В сочетании с вышеприведенным (и более важным) исправлением это, вероятно, даст вам значительное увеличение производительности.
Если вы планируете запускать этот алгоритм на гораздо более плотном наборе данных (таком, где число ребер приближается к | V| 2 / log | V |), тогда вы можете рассмотреть возможность перехода на алгоритм Floyd-Warshall .Запуск алгоритма Дейкстры один раз на узел (иногда называемый алгоритм Джонсона ) занимает время O (| V || E | log | V |), а использование Флойд-Варшалла - O (| V | 3) время.Тем не менее, для набора данных, о котором вы упомянули, график достаточно разрежен, чтобы нормально работать с несколькими экземплярами Дейкстры.
Надеюсь, это поможет!