图论-最短路Dijkstra算法详解超详 有图解

整体来看dij就是从起点开始扩散致整个图的过程,为什么说他稳定呢,是因为他每次迭代,都能得到至少一个结点的最短路。(不像SPFA,玄学复杂度)
但是他的缺点就是不能处理带负权值的边,和代码量稍稍复杂。

dij算法(采用方法邻接表+优先队列优化)复杂度O(mn)降为O(mlogn)
不多哔哔,我们直接看图解:
核心:每次去往距离起点最近的那个点,并且是第一次访问
图中用黄色来标记哪些点已经走过。

之前刷过几个dij的图论题,有兴趣的可以去我的博客看一下图论刷水题记录(一)(最短路-----dijkstra算法)
本来没打算写这个算法详解,但是上导论课的时候老师提到过,还要做作业,所以要写就写的详细一点吧,直接用老师的图来进行说明
在这里插入图片描述

手动模拟一下算法过程:
1.我们设置一个数组dis[20]用来储存到达该点距离的最小值(实时状态),并且初始化他们的值为无穷大。
在这里插入图片描述2.从起点出发,标记起点,因为自己到自己的距离为0,所以v1->v1=0,更新v1的临边,更新好后如图所示:
在这里插入图片描述3.找到距离起点最近的点(如下图),并且更新他的临边,我们发现从此点到上方的点距离要小于之前更新过的值,故我们将7更新为6,并将此点右边的点更新为5.
在这里插入图片描述4.我们继续进行上述操作,找到距离起点最近的点,标记为走过,更新他的临边,我们发现从此点到他左上方的点要比之前更新过的值小,故将左上方点更新为8,并将他上方和右上方的点分别更新为16和14
在这里插入图片描述5.继续在未走过的点中寻找距离起点最短的点,发现是6,将其标记为走过,我们发现它可以往正上方去走,但是问题是8小于5+6,所谓不更新该点
在这里插入图片描述6.找到距离起点最短的点,标记该点,发现它可以去他右边这个点,并且8+5小于16,所以更新该点的值为13.
在这里插入图片描述7.找到距离起点最短的点,标记该点,发现没有可以更新的点。
在这里插入图片描述
8.找到距离起点最短的点,标记该点,发现没有可以更新的点。
全图点均已标记算法结束
在这里插入图片描述经过以上的步骤,我们可以求出所有的点距离起点的最短路

ps(外带一个用邻接表+优先队列优化过的程序)

#pragma GCC optimize(3,"Ofast","inline")
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <math.h>
#include <string>
#include <list>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <algorithm>
#include <stdlib.h>
#include <vector>
#define maxn  2010
//#define true false
//#define false true
const int MaxN = 0x3f3f3f3f;
const int MinN = 0xc0c0c00c;
const double pi = acos(-1);
typedef long long ll;
const int mod = 1e9 + 7;
using namespace std;

int t,n;
bool visited[maxn];
int dis[maxn];

struct wazxy{
    int v,val;
    wazxy(int v1,int e1){v=v1;val=e1;}
};
vector<wazxy> a[maxn];
struct node{
    int id,dis;
    node(int a,int b){id=a,dis=b;}
    bool operator < (const node & a)const
    {return dis>a.dis;}
};

void dij(){
    int s=1;
    dis[s]=0;
    priority_queue<node>q;
    q.push(node(s,dis[s]));
    while(!q.empty()){
        node temp=q.top();
        q.pop();
        if(visited[temp.id])  continue;
        visited[temp.id]=true;
        for(int i=0;i<a[temp.id].size();i++){
            wazxy node1=a[temp.id][i];
            if(visited[node1.v]) continue;
            if(dis[node1.v]>node1.val+temp.dis){
                dis[node1.v]=node1.val+temp.dis;
                q.push(node(node1.v,dis[node1.v]));
            }
        }
    }
    printf("%d",dis[n]);
}

int main()
{
    cin>>t>>n;
    memset(visited,false,sizeof(visited));
    memset(dis,MaxN,sizeof(dis));
    while(t--){
        int x,y,v;
        scanf("%d%d%d",&x,&y,&v);
        a[x].push_back(wazxy(y,v));
    }
    dij();
    return 0;
}

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值