Dijkstra算法优先队列实现与Bellman_Ford队列实现的理解


 1 /*
2 Dijkstra算法用优先队列来实现,实现了每一条边最多遍历一次。 要知道,我们从队列头部找到的都是到
3 已经"建好树"的最短距离以及该节点编号, 并由该节点去更新 树根 到其他点(被更新的节点可以在队列中
4 ,也可以是非队列中的节点)的距离 。
5
6 ////队列中的节点都是要等待更新的节点
7
8 如果某个节点从队列中出来的时候,如果cur.first != dist[cur.second] 就是 cur.second这个节点一开始
9 被更新的最短距离值 和 现在得到的最短距离的值dist[cur.second] 不想等,说明该节点已经被之前队列中
10 具有更短距离的节点更新过了,此时的dist[cur.second] 就是最终的值。
11 */
12 #include<iostream>
13 #include<queue>
14 #include<cstring>
15 #define N 1000
16 using namespace std;
17
18 class EDGE
19 {
20 public:
21 int u, v, w;
22 int next;//和节点 u 相连的下一条边的编号
23 };
24
25 EDGE edge[2*N];
26
27 typedef pair<int, int>pii;//pair<距离,节点号>
28
29 int first[N];//最多有N个节点 ,建立每个节点和其相连的边的关系
30 int dist[N];//源点到各个点的最短距离
31
32 int n, m;//节点数,边数
33
34 bool operator >(pii a, pii b)
35 {
36 if(a.first==b.first)
37 return a.second > b.second;
38 return a.first > b.first;//按照最短的距离值在队列的前段
39 }
40
41 priority_queue<pii, vector<pii>, greater<pii> >q;
42
43 void Dijkstra()
44 {
45 pii cur;
46 memset(dist, 0x3f, sizeof(dist));
47 dist[1]=0;//另节点 1 为源点
48 q.push(make_pair(0, 1));
49 while(!q.empty())
50 {
51 cur=q.top();
52 q.pop();
53 if(cur.first != dist[cur.second]) continue;// 不等于的话说明该节点的值已经经过其他节点松弛为更短的距离值了
54 for(int e=first[cur.second]; e!=-1; e=edge[e].next)
55 if(dist[edge[e].v]>dist[edge[e].u]+edge[e].w)
56 {
57 dist[edge[e].v]=dist[edge[e].u]+edge[e].w;
58 q.push(make_pair(dist[edge[e].v], edge[e].v));//将更新之后的节点的放入队列之中
59 }
60 }
61 }
62
63 int main()
64 {
65 int i;
66 cin>>n>>m;
67 for(i=1; i<=n; ++i)
68 first[i]=-1;
69 for(i=0; i<m; ++i)
70 {
71 cin>>edge[i].u>>edge[i].v>>edge[i].w;
72 edge[edge[i].u].next=first[edge[i].u];
73 first[edge[i].u]=i;
74 }
75 Dijkstra();
76 for(i=2; i<=n; ++i)
77 cout<<"1->"<<i<<":"<<dist[i]<<endl;
78 return 0;
79 }


 1 /*
2 Bellman_Ford算法用队列实现和 Dijkstra算法用优先队列来实现相同的地方是,都是 层次 更新到节点的最短距离,
3 不同的是在Dijkstra()算法中,一个节点只有一次机会进入队列,而Bellman_Ford算法中,每一个节点会有多次进入
4 队列的机会,为什么呢? 主要是Bellman_Ford算法中实现的是带有负权图的最短距离,因为负权的关系,这样可能使得某个
5 节点的最短路径的值一直被更新(比如存在负权回路的时候),所以被更新的节点一直会进入队列中
6 */
7 #include<iostream>
8 #include<queue>
9 #include<cstring>
10 #define N 1000
11 using namespace std;
12
13 class EDGE
14 {
15 public:
16 int u, v, w;
17 int next;//和节点 u 相连的下一条边的编号
18 };
19
20 EDGE edge[2*N];
21
22 int first[N];//最多有N个节点 ,建立每个节点和其相连的边的关系
23 int dist[N];//源点到各个点的最短距离
24 int cnt[N];//记录每个节点在队列中出现的次数
25 int vis[N];//记录当前的节点是否已经在队列中
26
27 int n, m;//节点数,边数
28
29
30 queue<int>q;
31
32 int Bellman_Ford()
33 {
34 int cur;
35 memset(dist, 0x3f, sizeof(dist));
36 dist[1]=0;//另节点 1 为源点
37 q.push(1);
38 while(!q.empty())
39 {
40 cur=q.front();
41 q.pop();
42 vis[cur]=0;//出队列
43 ++cnt[cur];
44 if(cnt[cur]>n-1)//如果不存在负权回路,那么某个节点的最多被更新的次数为 n-1 次
45 return 0;
46 for(int e=first[cur]; e!=-1; e=edge[e].next)
47 if(dist[edge[e].v]>dist[edge[e].u]+edge[e].w)
48 {
49 dist[edge[e].v]=dist[edge[e].u]+edge[e].w;
50 if(!vis[edge[e].v])//本跟新的节点没有在队列中
51 {
52 q.push(edge[e].v);//将更新之后的节点的放入队列之中
53 vis[edge[e].v]=1;//放入队列
54 }
55 }
56 }
57 return 1;
58 }
59
60 int main()
61 {
62 int i;
63 cin>>n>>m;
64 for(i=1; i<=n; ++i)
65 first[i]=-1;
66 for(i=0; i<m; ++i)
67 {
68 cin>>edge[i].u>>edge[i].v>>edge[i].w;
69 edge[edge[i].u].next=first[edge[i].u];
70 first[edge[i].u]=i;
71 }
72 if(!Bellman_Ford())//表示存在负权回路
73 cout<<"不存在最短路径"<<endl;
74 else
75 {
76 for(i=2; i<=n; ++i)
77 cout<<"1->"<<i<<":"<<dist[i]<<endl;
78 }
79 return 0;
80 }

Dijkstra算法优先队列实现与Bellman_Ford队列实现的理解

时间: 2024-10-12 20:08:10

Dijkstra算法优先队列实现与Bellman_Ford队列实现的理解的相关文章

(转)图算法单源最短路径Dijkstra算法(邻接表/邻接矩阵+优先队列STL)

一.前言 最短路径算法,顾名思义就是求解某点到某点的最短的距离.消耗.费用等等,有各种各样的描述,在地图上看,可以说是图上一个地点到达另外一个地点的最短的距离.比方说,我们把地图上的每一个城市想象成一个点,从一个城市到另一个城市的花费是不一样的.现在我们要从上海去往北京,需要考虑的是找到一条路线,使得从上海到北京的花费最小.有人可能首先会想到,飞机直达啊,这当然是时间消耗最小的方法,但是考虑到费用的高昂,这条线路甚至还不如上海到北京的高铁可取.更有甚者,假设国家开通了从上海到西藏,再从西藏到兰州

最短路算法 :Bellman-ford算法 &amp; Dijkstra算法 &amp; floyd算法 &amp; SPFA算法 详解

 本人QQ :2319411771   邮箱 : [email protected] 若您发现本文有什么错误,请联系我,我会及时改正的,谢谢您的合作! 本文为原创文章,转载请注明出处 本文链接   :http://www.cnblogs.com/Yan-C/p/3916281.html . 很早就想写一下最短路的总结了,但是一直懒,就没有写,这几天又在看最短路,岁没什么长进,但还是加深了点理解. 于是就想写一个大点的总结,要写一个全的. 在本文中因为邻接表在比赛中不如前向星好写,而且前向星效率并

单源最短路径算法——Bellman-ford算法和Dijkstra算法

 BellMan-ford算法描述 1.初始化:将除源点外的所有顶点的最短距离估计值 dist[v] ← +∞, dist[s] ←0; 2.迭代求解:反复对边集E中的每条边进行松弛操作,使得顶点集V中的每个顶点v的最短距离估计值逐步逼近其最短距离:(运行|v|-1次) 3.检验负权回路:判断边集E中的每一条边的两个端点是否收敛.如果存在未收敛的顶点,则算法返回false,表明问题无解:否则算法返回true,并且从源点可达的顶点v的最短距离保存在 dist[v]中. 1 BELLMAN-FORD

Dijkstra算法详解

前言 前几天研究的Bellman_Ford算法虽然可以算负权,可是时间复杂度高达O(NM),即使是采用了队列优化,也有可能被网格图卡回O(NM),所以今天我们就来研究一个新的,更快的,但同时只能在正权图上运行的算法:Dijkstra(朴素Dijkstra算法) Dijkstra基本思想及实现过程 我们首先需要以下几个数组:dist[],vis[],用邻接矩阵需要g[][],邻接表则需要v[],w[],head[],nxt[] 邻接表与邻接矩阵在此不做过多解释,不懂的同学请自行百度,dist[i]

Dijkstra 算法

最短路径算法的基础知识,参见 http://blog.csdn.net/pacosonswjtu/article/details/49894021 Dijkstra算法 涉及到的 优先队列的操作实现(该优先队列的数据类型不是 int , 而是 Distance),详情参见http://blog.csdn.net/pacosonswjtu/article/details/49923389 [1]Dijkstra 算法相关 1.1)贪婪算法一般分阶段去求解一个问题, 在每个阶段它都把当前出现的当做是

51nod-迷宫问题(Dijkstra算法)

Dijkstra算法 你来到一个迷宫前.该迷宫由若干个房间组成,每个房间都有一个得分,第一次进入这个房间,你就可以得到这个分数.还有若干双向道路连结这些房间,你沿着这些道路从一个房间走到另外一个房间需要一些时间.游戏规定了你的起点和终点房间,你首要目标是从起点尽快到达终点,在满足首要目标的前提下,使得你的得分总和尽可能大.现在问题来了,给定房间.道路.分数.起点和终点等全部信息,你能计算在尽快离开迷宫的前提下,你的最大得分是多少么? Dijkstra算法是一个经典的算法--他是荷兰计算机科学家D

Dijkstra算法

Dijkstra算法是一个经典的算法--他是荷兰计算机科学家Dijkstra于1959年提出的单源图最短路径算法.也是一个经典的贪心算法.所谓单源图 是规定一个起点的图,我们的最短路径都是从这个起点出发计算的.算法的适用范围是一个无向(或者有向图),全部边权都是非负数. 算法描写叙述: 节点集合V = {}空集合,距离初始化. 节点编号0..n – 1, 起点编号0≤ s < n. 距离数组 起点 d[s] = 0 其它 d[i] = ∞, 0 ≤ i < n,  i ≠ s. 循环n次 找到

Dijkstra算法 --- 单源最短路

Dijkstra算法适用于边权值为正的情况,可用于计算正权图上的单元最短路. 其伪代码如下: 设d[v0] = 0, 其他d[i] = INF 循环n次{ 在所有未标号的结点中,选取d值最小的结点x 给结点x加上永久标号 对于从x出发的所有边,执行松弛操作. } //松弛操作的伪代码如下: RELAX(u,v,w) if(u.d + w(u,v) < v.d){ v.d = w.d + w(u,v); pre[v] = u; } Dijkstra算法代码: /* Dijkstra 单源最短路算法

算法导论-第24章 Dijkstra算法

Dikstra算法解决的是有向图上单源最短路径问题(无向图可以看成有相反的两条有向边),且要求边的权重都是非负值. 算法导论用了很多引理,性质来证明Dijstra算法的正确性,这里不说了,也表达不明白,只说我理解的过程. 有一个图G( V,E) ,选定一个源点s,维护一个集合Q=V-s,  Q中点有一个d值表示此时从s到该点的已知距离,s.d=0 :初始化都为正无穷,表明不可达.然后对s点所连接的点(设为点集M)进行松弛操作,就是设点m属于M, m.d > s.d+ w(s,m) 则更新 m.d