zoukankan      html  css  js  c++  java
  • Dijkstra算法详解

    Part 1.Dijkstra算法是干嘛的

    Dijkstra 算法用于求图中任意两点之间的最短路径,或任意一点到其他到其他所有点的最短路径,即单源最短路。Dijkstra 算法只适用于所有边权都为非负数的图,如果边权为负,Dijkstra 算法就无能为力了。


    Part 2.算法流程

    这里用邻接矩阵存图。

    1. 将图分为两个集合:已知最短路成的定点集合 (P) 和未知最短路径的集合 (S)。用一个 book[] 数组记录那些点在集合 (P) 中,book[i]=true表示点 (i) 在集合中,book[i]=false 表示点 (i) 不在集合中。

    2. 将源点 (d) 到自己的最短路径设为 (0),其余的设为 (infty)。这里用dis[i]表示(d) 到点 (i) 的最短路径,同时将源点 (d) 加入到集合 (P) 中。

    3. (1)每次在集合S中选择一个里源点最近(即dis[i]最小)的点 (i),将 (i) 加入集合 (P)(即book[i]=true)。(2)同时考查每一条与 (i) 有边相连的点 (v),看看能否通过点 (i)(d)(v) 的距离缩短(即dis[v]=min(dis[v],dis[i]+e[i][v]))(也就是松弛)。

    4. 重复第3步,当集合 (S) 为空时,算法结束。

    code:

    // luogu-judger-enable-o2
    #include<bits/stdc++.h>
    using namespace std;
    #define inf 2147483647
    int dis[1005],e[1005][1005];
    bool book[1005];
    int main()
    {
    	int n,m,i,j,u,v,minh,s,a,b,c;
    	cin>>n>>m>>s;
    	for(i=1;i<=n;i++)
    		for(j=1;j<=n;j++)
    			if(i!=j)
    				e[i][j]=inf; 
    	for(i=1;i<=m;i++)
    	{
    		cin>>a>>b>>c;
    		if(a!=b) e[a][b]=c;
    	}
    	for(i=1;i<=n;i++) dis[i]=e[s][i];
    	book[s]=true;//2
    	for(i=1;i<=n-1;i++)
    	{
    		minh=inf;
    		for(j=1;j<=n;j++)
    		{
    			if(dis[j]<minh&&book[j]==false)
    			{
    				minh=dis[j];
    				u=j;//3(1)
    			}
    		}
    		book[u]=true;
    		for(v=1;v<=n;v++)//3(2)
    			if(e[u][v]<inf)
    				if(dis[v]>dis[u]+e[u][v])
    					dis[v]=dis[u]+e[u][v];
    	}
    	for(i=1;i<=n;i++) cout<<dis[i]<<" ";
    	return 0;
    }
    

    part 3.还能再优化吗

    上述流程的时间复杂度为 (mathcal O(n^2)),如果 (n) 大一点,那么就会T飞。

    注意到步骤3(2)之和与 (i) 周围的边的点松弛,于是我们就可以用邻接表存图,优化算法的常数。

    观察到步骤3(1)每次一个一个寻找距离最小的点非常耗时间,于是我们就用一个优先队列来实时存最小的点。(详见代码)

    这样就可以将时间复杂度优化到 (mathcal O((m+n)log n))

    code:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    using namespace std;
    const int N=100010,M=100010;//N:点数,M:边数
    int head[N],ver[M],edge[M],nxt[M],dis[N];
    bool book[N];
    int n,m,tot;
    priority_queue<pair<int,int> > que;//第一维:距离,第二维:编号 
    void add(int x,int y,int z)//构建邻接表 
    {
    	ver[++tot]=y;
    	edge[tot]=z;
    	nxt[tot]=head[x];
    	head[x]=tot;
    }
    void Dijkstra()
    {
    	memset(dis,0x3f,sizeof(dis));
    	memset(book,0,sizeof(book));
    	dis[1]=0;
    	que.push(make_pair(0,1));
    	while(que.size())
    	{
    		int x=que.top().second; que.pop();
    		if(book[x]) continue;
    		book[x]=true;//标记 
    		for(int i=head[x];i;i=nxt[i])
    		{
    			int y=ver[i],z=edge[i];
    			if(dis[y]>dis[x]+z)
    			{
    				dis[y]=dis[x]+z;
    				que.push(make_pair(-dis[y],y));
    			}
    		}
    	}
    }
    int main()
    {
    	scanf("%d %d",&n,&m);
    	for(int i=1;i<=m;i++)
    	{
    		int x,y,z;
    		scanf("%d %d %d",&x,&y,&z);
    		add(x,y,z);
    	}
    	Dijkstra();
    	for(int i=1;i<=n;i++) printf("%d ",dis[i]);
    	return 0;
    }
    
  • 相关阅读:
    正则表达式--hdu2206ip匹配
    win7查看隐藏分区
    我购买byd的几点逻辑
    html5笔记
    机器学习
    Popular Cows
    武大OJ 574. K-th smallest
    武大OJ 622. Symmetrical
    [HAOI2011]防线修建
    1185: [HNOI2007]最小矩形覆盖
  • 原文地址:https://www.cnblogs.com/juruo-zzt/p/11837422.html
Copyright © 2011-2022 走看看