洛谷P4779 单源最短路径与Dijkstra算法
(蒟蒻出品,欢迎指正)
Dijkstra算法(由于字母太多,以下统一用dij代替(逃
dij算法,使用广度优先搜索与贪心算法解决单源图的最短路径问题,不适用于有负权边的图。
时间复杂度:O(mlogn)//n为顶点数,m为边数。
算法思路:对于所需求解的图,首先假设任意两顶点之间距离为正无穷。然后开始加入边,更新当前该源点到其余顶点的最短距离,将没有加入已知集合的距离最小的点选出,确定此点与源点最短距离,重复上述操作直到所有已知条件加入集合。
实现步骤:
1,确定当前待求最短路径的起点与终点;
2,将除起点外所有点加入未知集合,并将起点加入已知集合,直至确定该点到起点最短路径;
3,依次更新起点到i的距离dis[i];
4,将未知集合dis中与起点距离最小x的加入已知集合;
5,同Floyd算法思想,若起点与n间距离大于起点到x距离加x到n距离,更新dis[n];
6,重复以上步骤直到终点进入已知集合,输出答案;
当然若使用邻接矩阵存储是很慢的,为了优化时间及方便懒人,我们请出亲爱的优先队列与链式前向星帮助实现算法。
于是板子题:https://www.luogu.com.cn/problem/P4779应运而生。
1 #include<bits/stdc++.h> 2 #define ff(i,s,e) for(int i=s;i<=e;i++) 3 using namespace std; 4 inline int read(){ 5 register int x=0,f=1; 6 register char ch=getchar(); 7 while(ch>'9'||ch<'0'){if(ch=='-') f=-1;ch=getchar();} 8 while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} 9 return x*f; 10 } 11 const int M=500002; 12 const int inf=0x3f3f3f3f; 13 int n,m,s; 14 int cnt,head[M]; 15 long long dis[M];//s到i最短路径 16 struct egde{ 17 int to,nxt,w; 18 }e[M]; 19 typedef pair<int,int> pir;//距离及当前所到点 20 priority_queue<pir,vector<pir>,greater<pir> >q;//小根堆 21 void add(int u,int v,int w){//链式前向星 22 e[++cnt].w=w; 23 e[cnt].to=v; 24 e[cnt].nxt=head[u]; 25 head[u]=cnt; 26 } 27 void dij(int s){ 28 ff(i,1,n) dis[i]=inf;//将s到每一个点的距离统一赋值正无穷 29 dis[s]=0;//s到自己的距离为0 30 q.push(pir(0,s));//将起点加入队列 31 while(!q.empty()){ 32 int f = q.top().first,u = q.top().second;//s到u最短距离为f 34 q.pop(); 35 if(f!=dis[u]) continue;//作用小到可以忽略的优化 36 for(int i=head[u];i;i=e[i].nxt){//枚举点u可以到达的点更新最短路径 37 int v=e[i].to,w=e[i].w;//当前所到下一个点及两点间权值 38 if(dis[v]>dis[u]+w){ 39 dis[v]=dis[u]+w;//若以u为中转点到v路径更短,更新 40 q.push(pir(dis[v],v));//将当前已知最短路径入队 41 } 42 } 43 } 44 } 45 int main(){ 46 n=read();m=read();s=read(); 47 ff(i,1,m){ 48 int u,v,w; 49 u=read();v=read();w=read(); 50 add(u,v,w); 51 } 52 dij(s); 53 ff(i,1,n) printf("%lld ",dis[i]); 54 return 0; 55 }
感谢大佬@硫化氢提供的模板。
浙公网安备 33010602011771号