图论——最短路——dijkstra算法菜鸡详解
思路
利用前向星存图,用优先队列找到与前一个点相邻的未访问过的最短路。从起点开始,一次次找与起点s相连的最短的路e,dis[e]=min(dis[e],dis[s]+w[e][s]),如果这个点被更新而且之前没有加到队列过,那么就把他加到队列里面。直到队列为空为止。
例题
洛谷P4779
题目描述:
给定一个 nn 个点,mm 条有向边的带非负权图,请你计算从 ss 出发,到每个点的距离。数据保证你能从 ss 出发到任意点。
输入格式:
第一行为三个正整数 n, m, s。 第二行起 mm 行,每行三个非负整数 ui,vi,wi,表示从ui到vi有一条权值为wi的有向边。
输出格式:
输出一行 nn 个空格分隔的非负整数,表示 ss 到每个点的距离。
dijkstra代码
#include<bits/stdc++.h>
using namespace std;
const int M = 2e5+5;
const int N = 1e5+5;
int n,m,s;
int vis[N],ru[N]={0};
struct ling{ //前向星的结构体
int e,w,next;
//e表示这条路终点,w表示路的长度,next表示上一个连接这条路的起点的终点
}dege[M];
int cnt=1,head[M];
void add(int u,int v,int w){ //前向星
dege[cnt].e=v;
dege[cnt].w=w;
dege[cnt].next=head[u];
head[u]=cnt++;
}
struct node{
int u,d;
//u表示这条路的起点,d表示这个起点到初始点的距离
node(int u,int d):u(u),d(d){}
bool operator < (const node &a)const{
return d>a.d; //最小堆
}
};
priority_queue<node> q;
void dijk(int s){
memset(ru,0,sizeof(ru));
memset(vis,0x3f,sizeof(vis));
vis[s]=0;
q.push(node(s,vis[s]));
while(!q.empty()){
node t = q.top();q.pop();
int u = t.u;
int d = t.d;
if(ru[u]) continue ;
//我第一次写成return,一直过不了……
//应该是找不到就找下一条路
ru[u]=1;
for(int i=head[u];i>0;i=dege[i].next){
int v = dege[i].e;
int w = dege[i].w;
if(vis[v]>d+w){
vis[v]=d+w;
q.push(node(v,vis[v]));
}
}
}
}
int main(){
ios::sync_with_stdio(false);
memset(head,-1,sizeof(head));
cin>>n>>m>>s;
while(m--){
int u,v,w;
cin>>u>>v>>w;
add(u,v,w);
}
dijk(s);
for(int i=1;i<=n;++i){
cout<<vis[i]<<" ";
}
}
总结
·dijkstra时间复杂度为(mlogm),算得上是比较快的了。
·但是他不能判断负权图,用的时候要注意哦!