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

Я пытался понять эту реализацию алгоритма Дейкстры на C и в то же время измените его так, чтобы был найден только кратчайший путь между двумя конкретными узлами (источник и пункт назначения).

Однако я не знаю точно, что делать. Как я это вижу, делать особо нечего, я не могу изменить d[] или prev[], потому что эти массивы объединяют некоторые важные данные для расчета кратчайшего пути.

Единственное, что я могу придумать, это остановить алгоритм, когда путь найден, то есть разорвать цикл, когда mini = destination когда он помечен как посещенный.

Могу ли я сделать что-то еще, чтобы сделать его лучше, или этого достаточно?

РЕДАКТИРОВАТЬ:
Хотя я ценю сделанные мне предложения, люди по-прежнему не могут точно ответить на мой вопрос. Все, что я хочу знать, это как оптимизировать алгоритм для поиска только кратчайшего пути между двумя узлами. Меня пока не интересуют все остальные общие оптимизации. Я имею в виду, что в алгоритме, который находит все кратчайшие пути от узла X ко всем другим узлам, как мне оптимизировать его для поиска только определенного пути?

P.S. Я только что заметил, что циклы for начинаются с 1 до <=, почему они не могут начинаться с 0 и продолжаться до <?


person rfgamaral    schedule 16.04.2010    source источник
comment
То, что вы предложили, теоретически является единственным, что вы можете сделать (и если вы немного подумаете, вы найдете доказательство того, почему это так). Если вы хотите ускорить выполнение самой программы, вы можете перефразировать вопрос как вопрос скорости в C, и я уверен, что некоторые из здешних гуру вам помогут.   -  person Vlad the Impala    schedule 17.04.2010


Ответы (3)


Реализация в вашем вопросе использует соседнюю матрицу, что приводит к реализации O (n ^ 2). Учитывая, что графы в реальном мире обычно разрежены, т.е. количество узлов n обычно очень велико, однако количество ребер намного меньше от n^2.

Вам лучше взглянуть на реализацию dijkstra на основе кучи.

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

#include<algorithm>
using namespace std;

#define MAXN 100
#define HEAP_SIZE 100
typedef int Graph[MAXN][MAXN];

template <class COST_TYPE>
class Heap
{
public:
    int data[HEAP_SIZE],index[HEAP_SIZE],size;
    COST_TYPE cost[HEAP_SIZE];
    void shift_up(int i)
    {
        int j;
        while(i>0)
        {
            j=(i-1)/2;
            if(cost[data[i]]<cost[data[j]])
            {
                swap(index[data[i]],index[data[j]]);
                swap(data[i],data[j]);
                i=j;
            }
            else break;
        }
    }
    void shift_down(int i)
    {
        int j,k;
        while(2*i+1<size)
        {
            j=2*i+1;
            k=j+1;
            if(k<size&&cost[data[k]]<cost[data[j]]&&cost[data[k]]<cost[data[i]])
            {
                swap(index[data[k]],index[data[i]]);
                swap(data[k],data[i]);
                i=k;
            }
            else if(cost[data[j]]<cost[data[i]])
            {
                swap(index[data[j]],index[data[i]]);
                swap(data[j],data[i]);
                i=j;
            }
            else break;
        }
    }
    void init()
    {
        size=0;
        memset(index,-1,sizeof(index));
        memset(cost,-1,sizeof(cost));
    }
    bool empty()
    {
        return(size==0);
    }
    int pop()
    {
        int res=data[0];
        data[0]=data[size-1];
        index[data[0]]=0;
        size--;
        shift_down(0);
        return res;
    }
    int top()
    {
        return data[0];
    }
    void push(int x,COST_TYPE c)
    {
        if(index[x]==-1)
        {
            cost[x]=c;
            data[size]=x;
            index[x]=size;
            size++;
            shift_up(index[x]);
        }
        else
        {
            if(c<cost[x])
            {
                cost[x]=c;
                shift_up(index[x]);
                shift_down(index[x]);
            }
        }
    }
};



int Dijkstra(Graph G,int n,int s,int t)
{
    Heap<int> heap;
    heap.init();
    heap.push(s,0);
    while(!heap.empty())
    {
        int u=heap.pop();
        if(u==t)
            return heap.cost[t];
        for(int i=0;i<n;i++)
            if(G[u][i]>=0)
                heap.push(i,heap.cost[u]+G[u][i]);
    }
    return -1;
}
person Yin Zhu    schedule 17.04.2010
comment
Насколько я могу судить, dijkstra на основе кучи в основном меняет способ извлечения минимума, верно? Сначала мне нужно реализовать мини-кучу. Но если подумать, самая большая проблема, с которой я столкнулся, это как использовать минимальную кучу в алгоритме. Не могу найти много информации об этом... - person rfgamaral; 17.04.2010
comment
afaik сначала вы просто вставляете все узлы в минимальную кучу [ o (log (n)) для каждого узла, который суммируется с o (nlog (n))], а затем вместо цикла, в котором вы ищете минимум, вы просто извлечь минимальный узел o (log (n)).... - person Ahmed Kotb; 17.04.2010
comment
@Nazgulled обратитесь к коду. Как вы можете видеть, алгоритм Дейкстры чрезвычайно короток, когда вы реализовали кучу. - person Yin Zhu; 17.04.2010
comment
Вам не нужно помещать весь код для кучи, у меня уже есть код C, который я сделал год назад или около того :) Тем не менее, я не совсем уверен, какие изменения нужно внести в код C, который я разместил выше. Но надо еще немного подумать... - person rfgamaral; 17.04.2010

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

В настоящее время вы ищете непосещенный узел с наименьшим расстоянием до источника.

1) Вы можете поддерживать отдельный «открытый» список, который будет становиться все меньше и меньше по мере повторения и, таким образом, постепенно уменьшая пространство поиска.

2) Если вы поддерживаете «закрытый» список (те узлы, которые вы посетили), вы можете проверить расстояние только для этих узлов. Это будет постепенно увеличивать ваше пространство поиска, но вам не нужно проверять все узлы на каждой итерации. Проверка расстояния по узлам, которые еще не были посещены, не имеет смысла.

Кроме того: возможно, следует рассмотреть график при выборе следующего узла для оценки: в «закрытом» списке вы можете искать наименьшее расстояние, а затем искать «открытый» узел среди его соединений. (если узел не имеет открытых узлов в своих соединениях, вы можете удалить его из закрытого списка; тупик). Вы даже можете использовать это подключение для формирования открытого списка, это также поможет с островами (ваш код в настоящее время будет аварийно завершать работу, если на вашем графике есть острова).

Вы также можете предварительно построить более эффективный граф соединений вместо кросс-таблицы, содержащей все возможные комбинации узлов (например, структуру узла со списком узлов соседей []). Это избавит вас от необходимости проверять все узлы для каждого узла в массиве dist[][]

Вместо того, чтобы инициализировать все расстояния узлов до бесконечности, вы можете инициализировать их до «наименьшего возможного оптимистического расстояния» до цели и предпочесть обработку узлов на основе этого (здесь ваши возможности различаются, если узлы находятся на 2D-плоскости, вы можете использовать расстояние от птицы ). См. описания A* для эвристики. Однажды я реализовал это вокруг очереди, не совсем уверенный, как бы я интегрировал это в этот код (то есть без очереди).

person Community    schedule 17.04.2010
comment
Я не понимаю ваш первый абзац. Во-вторых, моя структура графа уже представляет собой связанный список, я просто использую эту ссылку, чтобы понять алгоритм Дейкстры, мой граф не является матрицей. Что касается третьего, то веса на моем графике не меньше 1 и не больше 3, помогает? Что мне поставить вместо бесконечности и как это поможет? - person rfgamaral; 17.04.2010
comment
Ваша таблица подключений dist[GRAPHSIZE][GRAPHSIZE]? Или я что-то где-то упускаю? Я имел в виду создание графа, который не содержит записей, где dist[n1][n2] == 0 - person ; 17.04.2010
comment
Что касается бесконечности, неважно, возможно, проще поискать путь A *, если интересно. Я уверен, что это будет намного яснее, чем любая попытка, которую я могу попытаться объяснить :-P - person ; 17.04.2010
comment
Расширенный первый абзац несколько объясняет открытый и закрытый список. Надеюсь, у меня есть смысл :-) - person ; 17.04.2010

Самое большое улучшение, которое вы можете сделать по сравнению с Дейкстрой, — это использовать вместо него A*. Конечно, для этого требуется наличие эвристической функции.

person rlbond    schedule 17.04.2010
comment
Это невозможно, у меня нет на это времени :( - person rfgamaral; 17.04.2010
comment
На самом деле A* — это всего лишь несколько небольших изменений по сравнению с Дейкстрой. - person rlbond; 17.04.2010