Dijkstra算法及堆优化的dijkstra

dijkstra只能处理没有负权边的图,相较于spfa算法更适用于稠密图,因为spfa算法的时间复杂度最坏是O(nm)如果m=n2,那么时间复杂度就很差了,如果有些题特意卡你spfa,就必须用dijkstra或者堆优化的Dijkstra了。
dijkstra分为未堆优化的和堆优化的两种,未堆优化的时间复杂度是O(n2),堆优化的时间复杂度是O((n+m)logn)。
算法思想:
我们可以把整个图的所有点分成两个集合S,U。S代表的是已经求出的到顶点s(源点)的顶点集合。U表示还未求出的最短路径的顶点集合。
初始时,S中只有起点s,U中是除s之外的所有顶点,然后从U中找出路径最短的顶点,并将其加入到S中;接着,更新U中的顶点和顶点对应的路径。 然后,再从U中找出路径最短的顶点,并将其加入到S中;接着,更新U中的顶点和顶点对应的路径。 … 重复该操作,直到遍历完所有顶点。
实现方法:
1,初始时,S只包含起点s;U包含除s外的其他顶点,且U中顶点的距离为”起点s到该顶点的距离”[例如,U中顶点v的距离为(s,v)的长度,然后s和v不相邻,则v的距离为∞]。
2,从U中选出”距离最短的顶点k”,并将顶点k加入到S中;同时,从U中移除顶点k。
3,更新U中各个顶点到起点s的距离。之所以更新U中顶点的距离,是由于上一步中确定了k是求出最短路径的顶点,从而可以利用k来更新其它顶点的距离;例如,(s,v)的距离可能大于(s,k)+(k,v)的距离。
4,重复步骤(2)和(3),直到遍历完所有顶点。
图解:
以顶点D为起点,下图中的B(23 )应为B(13)。在这里插入图片描述

未堆优化的Dijkstra:这里存图的方式是链式前向星,就是一种用数组模拟链表的过程。着重理解一下数组vis[],vis[i]=1表示节点I从上述的集合U转移到了集合S,也就是说明了节点I到原点的最短距离已经找到了

#include<iostream>
#include<cstring>
#define maxn 10005
#define inf 2147483647
using namespace std;
int n,m,s;
int head[maxn],dis[maxn];
bool vis[maxn];
int t;
struct edge{
 int from,to,w,next;
}e[500005];
void add(int u,int v,int w){
 e[t].from =u;
 e[t].to =v;
 e[t].w =w;
 e[t].next =head[u];
 head[u]=t++;
}
void dijkstra(int s){
 for(int i=1;i<=n;i++)dis[i]=inf;
 dis[s]=0;
 for(int i=head[s];i!=-1;i=e[i].next ){
  int v=e[i].to ;
  if(dis[v]>dis[s]+e[i].w )dis[v]=dis[s]+e[i].w ;
 }
 vis[s]=1;
 for(int i=1;i<n;i++){
  int minw=inf,id;
  for(int j=1;j<=n;j++){
   if(dis[j]<minw&&!vis[j]){
    minw=dis[j];
    id=j;
   }
  }
  vis[id]=1;
  for(int i=head[id];i!=-1;i=e[i].next ){
   int v=e[i].to ;
   if(dis[v]>dis[id]+e[i].w )
   dis[v]=dis[id]+e[i].w ;
  }
 }
}
int main(){
 memset(head,-1,sizeof(head));
 cin>>n>>m>>s;
 int u,v,w;
 for(int i=1;i<=m;i++){
  cin>>u>>v>>w;
  add(u,v,w);
 }
 dijkstra(s);
 for(int i=1;i<=n;i++)cout<<dis[i]<<" ";cout<<endl;
} 

堆优化的dijkstra:
分析上面的代码,我们每次都要遍历所有节点来找到最新的距离源点最近的点,扫一遍是O(n),如果我们建立一个最小堆,把更新的点都丢到最小堆里面去,每次直接取出堆顶元素就是距离源点最近的节点了。
因为priority_queue默认是最大堆,所以我们需要重载一下符号’<'实现最小堆。一旦节点从最小堆里被抛了出来,也就是上面的从集合U转移到了集合S,即节点i到原点的最短距离已经找到了。

#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#define maxn 100010
#define inf 1e8
using namespace std;
int n,m,s,t;
int head[maxn],dis[maxn];
bool vis[maxn];
struct edge{
 int to,w,next;
}e[2*maxn];
int cnt;
void add(int u,int v,int w){
 e[++cnt].to =v;
 e[cnt].w =w;
 e[cnt].next =head[u];
 head[u]=cnt;
}
struct node{
 int id,dis;
 bool operator<(const node &a)const{
  return dis>a.dis ;
 }
};
void duijkstra(int s){
 for(int i=1;i<maxn;i++)dis[i]=inf,vis[i]=0;
 priority_queue<node>q;
 dis[s]=0;
 node temp;temp.id =s,temp.dis =dis[s];
 q.push(temp); 
 while(q.size() ){
  node temp=q.top() ;q.pop() ;
  int u=temp.id ,w=temp.dis ;
  if(vis[u])continue;
  vis[u]=1;
  for(int i=head[u];i;i=e[i].next ){
   int v=e[i].to ;
   if(dis[v]>w+e[i].w ){
    dis[v]=w+e[i].w ;
    node temp;temp.id =v,temp.dis =dis[v];
    q.push(temp); //这里vis[v]一定是0,因为vis[]=1的节点已经是最短距离了,不可能被更新。
   }
  }
 }
}
int main(){
 cin>>n>>m>>s>>t;
 int u,v,w;
 for(int i=1;i<=m;i++){
  scanf("%d%d%d",&u,&v,&w);
  add(u,v,w);
  add(v,u,w);
 }
 duijkstra(s);
 cout<<dis[t]<<endl;
 return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值