5

我试图在 Dijkstra 算法的 C 中理解这个实现,同时修改它,以便只找到 2 个特定节点(源和目标)之间的最短路径。

但是,我不知道该怎么做。在我看来,没什么可做的,我似乎无法更改d[]prev[]导致这些数组聚合一些重要数据以进行最短路径计算。

我唯一能想到的就是在找到路径时停止算法,也就是说,mini = destination当它被标记为已访问时打破循环。

我还能做些什么来让它变得更好,或者这就足够了吗?

编辑:
虽然我很欣赏给我的建议,但人们仍然无法准确回答我的问题。我只想知道如何优化算法以仅搜索2 个节点之间的最短路径。目前,我对所有其他一般优化不感兴趣。我要说的是,在找到从节点 X 到所有其他节点的所有最短路径的算法中,如何优化它以仅搜索特定路径?

PS:我刚刚注意到for循环从1until开始<=,为什么它不能从0until开始<

4

3 回答 3

5

您问题中的实现使用相邻矩阵,它导致 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;
}
于 2010-04-17T03:18:29.680 回答
2

通过维护一个单独的打开和关闭列表(已访问和未访问),您可能会有所改善,它可能会稍微缩短搜索时间。

当前,您搜索到源距离最短的未访问节点。

1)您可以维护一个单独的“开放”列表,随着您的迭代,它会变得越来越小,从而使您的搜索空间逐渐变小。

2)如果您维护一个“封闭”列表(您访问的那些节点),您可以仅检查这些节点的距离。这将逐渐增加您的搜索空间,但您不必每次迭代都检查所有节点。对尚未访问的节点的距离检查没有任何意义。

另外:在选择下一个要评估的节点时,可能考虑遵循图表:在“封闭”列表中,您可以寻找最小距离,然后在其连接中搜索“开放”节点。(如果该节点的连接中没有打开的节点,您可以将其从封闭列表中删除;死胡同)。您甚至可以使用此连接来形成您的开放列表,这也有助于岛(如果您的图表有岛,您的代码当前将崩溃)。

您还可以预先构建更有效的连接图,而不是包含所有可能节点组合的交叉表(例如,具有 neighbours[] 节点列表的 Node 结构)。这将消除必须检查 dist[][] 数组中每个节点的所有节点

除了将所有节点距离初始化为无穷大,您还可以将它们初始化为到目标的“最小可能乐观距离”并基于此进行节点处理(您的可能性在这里有所不同,如果节点位于 2D 平面上,您可以使用 Bird-distance )。请参阅启发式的 A* 描述。我曾经围绕一个队列实现了这个,不完全确定我将如何将它集成到这个代码中(没有队列)。

于 2010-04-17T00:45:07.113 回答
1

您可以对 Dijkstra 做出的最大改进是改用A*。当然,这需要你有一个启发式函数。

于 2010-04-17T03:10:20.127 回答