Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/64.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 迪克斯特拉';s算法:为什么需要在队列中查找最小距离元素_C_Algorithm_Graph_Shortest Path_Dijkstra - Fatal编程技术网

C 迪克斯特拉';s算法:为什么需要在队列中查找最小距离元素

C 迪克斯特拉';s算法:为什么需要在队列中查找最小距离元素,c,algorithm,graph,shortest-path,dijkstra,C,Algorithm,Graph,Shortest Path,Dijkstra,我编写了Dijksta算法的这个实现,它在循环的每次迭代中而Q不是空的而不是找到队列的最小元素,它占据队列的头部 这是我写的代码 #include <stdio.h> #include <limits.h> #define INF INT_MAX int N; int Dist[500]; int Q[500]; int Visited[500]; int Graph[500][500]; void Dijkstra(int b){ int H = 0;

我编写了Dijksta算法的这个实现,它在循环的每次迭代中
而Q不是空的
而不是找到队列的最小元素,它占据队列的头部

这是我写的代码

#include <stdio.h>
#include <limits.h>

#define INF INT_MAX
int N;
int Dist[500];
int Q[500];
int Visited[500];
int Graph[500][500];

void Dijkstra(int b){
     int H = 0;
     int T = -1;
     int j,k;

Dist[b] = 0;

Q[T+1] = b;
T = T+1;

while(T>=H){
    j = Q[H];
    Visited[j] = 1;
    for (k = 0;k < N; k++){
        if(!Visited[k] && Dist[k] > Graph[j][k] + Dist[j] && Graph[j][k] != -1){
            Dist[k] = Dist[j]+Graph[j][k];
            Q[T+1] = k;
            T = T+1;
        }
    }

    H = H+1;
}
}  

int main(){

int src,target,m;
int a,w,b,i,j;

scanf("%d%d%d%d",&N,&m,&src,&target);

for(i = 0;i < N;i ++){
    for(j = 0;j < N;j++){
        Graph[i][j] = -1;
    }
}

for(i = 0; i< N; i++){
    Dist[i] = INF;
    Visited[i] = 0;
}


for(i = 0;i < m; i++){
    scanf("%d%d%d",&a,&b,&w);
    a--;
    b--;
    Graph[a][b] = w;
    Graph[b][a] = w;
}

Dijkstra(src-1);


if(Dist[target-1] == INF){
    printf("NO");
}else {
    printf("YES\n%d",Dist[target-1]);
}

return 0;
}
#包括
#包括
#定义INF INT_MAX
int N;
国际区[500];
int Q[500];
国际访问[500];
int图[500][500];
迪杰克斯特拉(内部b){
int H=0;
int T=-1;
int j,k;
距离[b]=0;
Q[T+1]=b;
T=T+1;
而(T>=H){
j=Q[H];
访问量[j]=1;
对于(k=0;k图[j][k]+Dist[j]&图[j][k]!=-1){
Dist[k]=Dist[j]+图[j][k];
Q[T+1]=k;
T=T+1;
}
}
H=H+1;
}
}  
int main(){
int src,target,m;
int a,w,b,i,j;
scanf(“%d%d%d%d”、&N、&m、&src、&target);
对于(i=0;i
我对我找到的所有测试用例都运行了这个,它给出了正确的答案。

我的问题是为什么我们需要找到min?有人能用简单的英语给我解释一下吗?我还需要一个测试用例来证明我的代码是错误的。

看看这个示例:

1-(6)-> 2 -(7)->3
  \          /
   (7)     (2)
     \    /
       4
即,长度为6的边从1到2,长度为7的边从2到3,长度为7的边从1到4,以及长度为4到3的边。我相信你的算法会认为从1到3的最短路径长度为13到2,而实际上最好的解决方案是长度为9到4

希望这能说明问题

编辑:很抱歉,此示例没有阻止代码。看看这个:

8 9 1 3
1 5 6
5 3 2
1 2 7
2 3 2
1 4 7
4 3 1
1 7 3
7 8 2
8 3 2

您的输出是
是8
。而路径
1->7->8->3
只需要7。这里有一个链接,我认为你的代码的时间复杂度是错误的。您的代码比较(几乎)所有节点对,这是二次时间复杂度

尝试添加10000个节点和10000条边,看看代码是否能在1秒内执行

始终必须找出距离最小的未访问顶点,否则至少会得到一个顶点 边缘的形状是错误的。例如,考虑下面的案例

4
12 8
2 4 5
1 3 2
3.2.1

             (8)   (5)
           1-----2----4
            \   /  
          (2)\ / (1) 
              3
我们从顶点1开始

distance[1]=0
当您访问
顶点1
时,您放松了
顶点2
顶点3
所以现在

距离[2]=8
距离[3]=2

在此之后,如果我们不选择最小值,而是选择顶点2,我们得到

距离[4]=13

然后选择顶点3,它将给出

distance[2]=3
因此,我们得到的距离[4]=13

距离[4]=8


因此,我们应该在Dijkstra的每个阶段从未访问中选择最小值,这可以通过使用
优先级\u队列

有效地完成。如果为下图运行算法,它取决于子级的顺序。假设我们正在寻找从1到4的最短路径

如果从队列1开始

dist[1] = 0
dist[2] = 21
dist[3] = 0
当使用
2
3
推送队列时,如果我们从队列中消耗2,它将使
dist[4]=51
seen={1,2}
q=[
1
2
,3,4]
下次从队列中使用
3
时,将不会再次将
2
添加到队列中,因为它已在
中查看。因此,该算法稍后会将距离从
1->3-5->4
的路径更新为12+31=43,但最短路径是32,它位于
1->3->2->4

让我用代码示例讨论一些其他方面。假设我们有一个
(u,v,w)
的连接列表,其中节点
u
有一个到
v
的加权定向边,其权重
w
。让我们准备图和边,如下所示:

graph, edges = {i: set() for i in range(1, N+1)}, dict()
for u,v,w in connection_list:
    graph[u].add(v)
    edges[(u,v)] = w
算法1-如果未访问,则选择要添加的任何子项 上面已经讨论过这个问题,对于1和4之间的最短路径,它将给出错误的结果43,而不是32

问题是没有将2重新添加到队列中,然后让我们将
seen
和孩子们再次删除

算法2-再次将所有子级添加到队列中 在这种情况下,这将起作用,但它仅适用于本例。这个算法有两个问题

  • 我们再次添加相同的节点,因此对于更大的示例,复杂性将取决于边的数量
    E
    ,而不是节点的数量
    V
    ,对于稠密图,我们可以假设
    O(E)=O(N^2)
  • 如果我们在图中添加循环,它将永远运行,因为没有停止的检查。所以这个算法不适合循环图
  • 所以,这就是为什么我们必须花费额外的时间来选择最小的子对象,如果我们使用线性搜索,我们将得到与上面相同的复杂性。但是如果我们使用优先级队列,我们可以将最小搜索减少到
    O(lgN)
    ,而不是
    O(N)
    。下面是代码的线性搜索更新

    算法3-带线性最小搜索的Dijkstra算法
    现在我们知道了下一次使用堆来获得最佳Dijkstra算法的思维过程。

    我尝试了这个输入(
    413\n126\n2 37\n147\n432\n
    ),这给了我
    YES\n9\n
    。显然这是正确的答案,所以这不是反例。很抱歉你是对的。我正在添加一个有效的示例。我不会画它,因为它非常大。所以问题是节点的数量很重要
    q = deque([start])
    seen = set()
    dist = {i:float('inf') for i in range(1, N+1)}
    dist[start] = 0
    
    while q:
        top = q.pop()
        seen.add(top)
        for v in graph[top]:
            dist[v] = min(dist[v], dist[top] + edges[(top, v)])
            if v not in seen:
                q.appendleft(v)
    
    while q:
        top = q.pop()
        seen.add(top)
        for v in graph[top]:
            dist[v] = min(dist[v], dist[top] + edges[(top, v)])
            q.appendleft(v)
    
    q = [K]
    seen = set()
    dist = {i:float('inf') for i in range(1, N+1)}
    dist[start] = 0
    
    while q:
        min_dist, top = min((dist[i], i) for i in q)
        q.remove(top)
        seen.add(top)
        for v in graph[top]:
            dist[v] = min(dist[v], dist[top] + edges[(top, v)])
            if v not in seen:
                q.append(v)