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

/*
Dijkstra算法用优先队列来实现,实现了每一条边最多遍历一次。 要知道,我们从队列头部找到的都是到
已经"建好树"的最短距离以及该节点编号, 并由该节点去更新 树根 到其他点(被更新的节点可以在队列中
,也可以是非队列中的节点)的距离 。

////如果v节点的到更新,则直接放入队列中(pair<d[v], v>)不会重复放入到队列中

如果某个节点从队列中出来的时候,如果cur.first != dist[cur.second] 就是 cur.second这个节点一开始
被更新的最短距离值 和 现在得到的最短距离的值dist[cur.second] 不想等,说明该节点已经被之前队列中
具有更短距离的节点更新过了, 那么新的节点pair(dist[cur.second], cur.second)再次放入优先队列中,用来跟新其他节点的最短距离。 如果想等,则dist[cur.second]就是cur.second最终的最短距离!
*/
#include<iostream>
#include<queue>
#include<cstring>
#define N 1000
using namespace std;

class EDGE
{
  public:
    int u, v, w;
    int next;//和节点 u 相连的下一条边的编号
};

EDGE edge[2*N];

typedef pair<int, int>pii;//pair<距离,节点号>

int first[N];//最多有N个节点 ,建立每个节点和其相连的边的关系
int dist[N];//源点到各个点的最短距离 

int n, m;//节点数,边数 

bool operator >(pii a, pii b)
{
   if(a.first==b.first)
     return a.second > b.second;
   return a.first > b.first;//按照最短的距离值在队列的前段
}

priority_queue<pii, vector<pii>, greater<pii> >q; 

void Dijkstra()
{
   pii cur;
   memset(dist, 0x3f, sizeof(dist));
   dist[1]=0;//另节点 1 为源点
   q.push(make_pair(0, 1));
   while(!q.empty())
   {
      cur=q.top();
      q.pop();
      if(cur.first != dist[cur.second])  continue;// 不等于的话说明该节点的值已经经过其他节点松弛为更短的距离值了
      for(int e=first[cur.second]; e!=-1; e=edge[e].next)
        if(dist[edge[e].v]>dist[edge[e].u]+edge[e].w)
        {
               dist[edge[e].v]=dist[edge[e].u]+edge[e].w;
               q.push(make_pair(dist[edge[e].v], edge[e].v));//将更新之后的节点的放入队列之中
        }
   }
}

int main()
{
   int i;
   cin>>n>>m;
   for(i=1; i<=n; ++i)
     first[i]=-1;
   for(i=0; i<m; ++i)
   {
       cin>>edge[i].u>>edge[i].v>>edge[i].w;
       edge[edge[i].u].next=first[edge[i].u];
       first[edge[i].u]=i;
   }
   Dijkstra();
   for(i=2; i<=n; ++i)
     cout<<"1->"<<i<<":"<<dist[i]<<endl;
   return 0;
}
/*
Bellman_Ford算法用队列实现和 Dijkstra算法用优先队列来实现相同的地方是,都是 层次 更新到节点的最短距离,
都是将具有最短距离的节点(如果不在队列中)放入队列中
Bellman_Ford算法中实现的是带有负权图的最短距离,因为负权的关系,这样可能使得某个
节点的最短路径的值一直被更新(比如存在负权回路的时候),所以被更新的节点(如果不在队列中)一直会进入队列中
*/
#include<iostream>
#include<queue>
#include<cstring>
#define N 1000
using namespace std;

class EDGE
{
  public:
    int u, v, w;
    int next;//和节点 u 相连的下一条边的编号
};

EDGE edge[2*N];

int first[N];//最多有N个节点 ,建立每个节点和其相连的边的关系
int dist[N];//源点到各个点的最短距离
int cnt[N];//记录每个节点在队列中出现的次数
int vis[N];//记录当前的节点是否已经在队列中 

int n, m;//节点数,边数 

queue<int>q; 

int Bellman_Ford()
{
   int cur;
   memset(dist, 0x3f, sizeof(dist));
   dist[1]=0;//另节点 1 为源点
   q.push(1);
   while(!q.empty())
   {
      cur=q.front();
      q.pop();
      vis[cur]=0;//出队列
      ++cnt[cur];
      if(cnt[cur]>n-1)//如果不存在负权回路,那么某个节点的最多被更新的次数为 n-1 次
         return 0;
      for(int e=first[cur]; e!=-1; e=edge[e].next)
        if(dist[edge[e].v]>dist[edge[e].u]+edge[e].w)
        {
               dist[edge[e].v]=dist[edge[e].u]+edge[e].w;
               if(!vis[edge[e].v])//本跟新的节点没有在队列中
               {
                  q.push(edge[e].v);//将更新之后的节点的放入队列之中
                  vis[edge[e].v]=1;//放入队列
        }
        }
   }
   return 1;
}

int main()
{
   int i;
   cin>>n>>m;
   for(i=1; i<=n; ++i)
     first[i]=-1;
   for(i=0; i<m; ++i)
   {
       cin>>edge[i].u>>edge[i].v>>edge[i].w;
       edge[edge[i].u].next=first[edge[i].u];
       first[edge[i].u]=i;
   }
   if(!Bellman_Ford())//表示存在负权回路
      cout<<"不存在最短路径"<<endl;
   else
   {
     for(i=2; i<=n; ++i)
       cout<<"1->"<<i<<":"<<dist[i]<<endl;
   }
   return 0;
}
时间: 2024-11-08 17:28:36

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

Dijkstra算法(二) C++详解

迪杰斯特拉算法介绍 迪杰斯特拉(Dijkstra)算法是典型最短路径算法,用于计算一个节点到其他节点的最短路径. 它的主要特点是以起始点为中心向外层层扩展(广度优先搜索思想),直到扩展到终点为止. 基本思想 通过Dijkstra计算图G中的最短路径时,需要指定起点s(即从顶点s开始计算). 此外,引进两个集合S和U.S的作用是记录已求出最短路径的顶点(以及相应的最短路径长度),而U则是记录还未求出最短路径的顶点(以及该顶点到起点s的距离). 初始时,S中只有起点s:U中是除s之外的顶点,并且U中

最短路径算法-Dijkstra算法的应用之单词转换(词梯问题)(转)

一,问题描述 在英文单词表中,有一些单词非常相似,它们可以通过只变换一个字符而得到另一个单词.比如:hive-->five:wine-->line:line-->nine:nine-->mine..... 那么,就存在这样一个问题:给定一个单词作为起始单词(相当于图的源点),给定另一个单词作为终点,求从起点单词经过的最少变换(每次变换只会变换一个字符),变成终点单词. 这个问题,其实就是最短路径问题. 由于最短路径问题中,求解源点到终点的最短路径与求解源点到图中所有顶点的最短路径复

Dijkstra算法【模板】

1.定义概览 Dijkstra(迪杰斯特拉)算法是典型的单源最短路径算法,用于计算一个节点到其他所有节点的最短路径.主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止.Dijkstra算法是很有代表性的最短路径算法,在很多专业课程中都作为基本内容有详细的介绍,如数据结构,图论,运筹学等等.注意该算法要求图中不存在负权边. 问题描述:在无向图 G=(V,E) 中,假设每条边 E[i] 的长度为 w[i],找到由顶点 V0 到其余各点的最短路径.(单源最短路径)   2.算法描述 1)算法思想

最短路径之Dijkstra算法

Dijkstra算法: 首先,引进一个辅助向量D,它的每个分量D[i]表示当前所找到的从始点v到每个终点vi的的长度:如D[3]=2表示从始点v到终点3的路径相对最小长度为2.这里强调相对就是说在算法过程中D的值是在不断逼近最终结果但在过程中不一定就等于长度.它的初始状态为:若从v到vi有弧,则D为弧上的权值:否则置D为∞.显然,长度为 D[j]=Min{D | vi∈V} 的路径就是从v出发的长度最短的一条.此路径为(v,vj). 那么,下一条长度次短的是哪一条呢?假设该次短路径的终点是vk,

Dijkstra算法(三) Java详解

迪杰斯特拉算法介绍 迪杰斯特拉(Dijkstra)算法是典型最短路径算法,用于计算一个节点到其他节点的最短路径. 它的主要特点是以起始点为中心向外层层扩展(广度优先搜索思想),直到扩展到终点为止. 基本思想 通过Dijkstra计算图G中的最短路径时,需要指定起点s(即从顶点s开始计算). 此外,引进两个集合S和U.S的作用是记录已求出最短路径的顶点(以及相应的最短路径长度),而U则是记录还未求出最短路径的顶点(以及该顶点到起点s的距离). 初始时,S中只有起点s:U中是除s之外的顶点,并且U中

Dijkstra算法(一) C语言详解

迪杰斯特拉算法介绍 迪杰斯特拉(Dijkstra)算法是典型最短路径算法,用于计算一个节点到其他节点的最短路径. 它的主要特点是以起始点为中心向外层层扩展(广度优先搜索思想),直到扩展到终点为止. 基本思想 通过Dijkstra计算图G中的最短路径时,需要指定起点s(即从顶点s开始计算). 此外,引进两个集合S和U.S的作用是记录已求出最短路径的顶点(以及相应的最短路径长度),而U则是记录还未求出最短路径的顶点(以及该顶点到起点s的距离). 初始时,S中只有起点s:U中是除s之外的顶点,并且U中

dijkstra标记算法-Dijkstra标记算法与Dijkstra算法的区别

问题描述 Dijkstra标记算法与Dijkstra算法的区别 请问离散数学中用Dijkstra标记算法求最短链与用Dijkstra算法求最短路径的联系 解决方案 dijkstra算法最短路径-Dijkstra算法Prim算法与Dijkstra算法的区别 解决方案二: 二者不是同一种算法吗?没有听说过迪杰斯特拉算法还分几种的啊.

【算法导论】单源最短路径之Dijkstra算法

        Dijkstra算法解决了有向图上带正权值的单源最短路径问题,其运行时间要比Bellman-Ford算法低,但适用范围比Bellman-Ford算法窄. 迪杰斯特拉提出的按路径长度递增次序来产生源点到各顶点的最短路径的算法思想是:对有n个顶点的有向连通网络G=(V, E),首先从V中取出源点u0放入最短路径顶点集合U中,这时的最短路径网络S=({u0}, {}); 然后从uU和vV-U中找一条代价最小的边(u*, v*)加入到S中去,此时S=({u0, v*}, {(u0,

Dijkstra算法 c语言实现

 Dijkstra(迪杰斯特拉)算法是典型的最短路径路由算法,用于计算一个节点到其他所有节点的最短路径.主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止.Dijkstra算法能得出最短路径的最优解,但由于它遍历计算的节点很多,所以效率低. Dijkstra算法是很有代表性的最短路算法,在很多专业课程中都作为基本内容有详细的介绍,如数据结构,图论,运筹学等等. 其基本思想是,设置顶点集合S并不断地作贪心选择来扩充这个集合.一个顶点属于集合S当且仅当从源到该顶点的最短路径长度已知. 初始时,