【最短路】Djikstra算法

作为一名蓝桥杯er(今年acm成绩并不理想),还有一个星期,蓝桥杯国赛就要到来,我肯定是希望能够拿到国赛一等奖的,也有可能事与愿违;

总之现在来讲一下常用的Djikstra算法,效率高但是不支持负权,而之前写的bellmanford能够支持负权环,至于能够支持负权环的floyd算法,可能得下次再学;

至于存图结构,我想了一下,邻接表和链式前向星可能差不多,而邻接矩阵太慢,具体可以看这篇文章链式前向星,也可以看我的前一篇文章,总之,链式前向星我认为是一个很好用,很好理解并且很好写的数据结构。

对于最短路算法,我觉得bellmanford算法很像dfs,而Djikstra像bfs,可以看我之前写的DFS和BFS,一个是一直遍历到最内层(尽管“松弛”操作使得循环并不是一次进行到底),另一个则是将每一层单独放进一个队列并且进行遍历,结构上都非常相似(以上是笔者的一些理解,可能有些人学的板子和我的不一样,不要见怪),而且笔者不会制作动图和动态视频,这个资源在网上随便能找到,如果对文字说明还是不能理解的话就去找个视频看看。

存图在这里也不过多赘述,这里直接上代码

vector<ll>dist(n+1,INT_MAX);//1到每个点的距离,初始为无限远
    vector<bool>vis(n+1,false);//走过的就不再走,避免重复操作
    dist[1]=0;
    priority_queue<pair<ll,ll>,vector<pair<ll,ll>>,greater<pair<ll,ll>>>pq;
    //first是当前的距离,second是当前的节点
    pq.push({dist[1],1});//放入第一个元素,进入循环
    while(pq.size())
    {
        ll crrDist=pq.top().first;//这句可以不要,为了规范理解所以保留
        ll u=pq.top().second;//本次的起点
        pq.pop();
        if(vis[u])continue;//如果走过就跳过
        vis[u]=true;//标记
        for(ll i=head[u];i!=-1;i=edge[i].next)//循环这个节点的每一个子节点
        {
            dist[edge[i].goal]=min(dist[edge[i].goal],dist[u]+edge[i].value);//松弛
            pq.push({dist[edge[i].goal],edge[i].goal});//推入下一个节点
        }
    }

可见vis数组,以及队列(此处因为要找最短路所以使用小根堆,也可以全部存进队列然后再遍历比较大小,尽管这个操作显得多余且时效性不如优先队列)和BFS的代码如出一辙,只是稍加修改,能够理解代码就说明学会了(

### Dijkstra算法概述 Dijkstra算法是一种著名的图论算法,专门用于解决单源短路径问题。该算法由荷兰计算机科学家Edsger W. Dijkstra于1956年提出[^1]。 #### 算法适用范围 此算法适用于带权重的有向图或无向图中的边权值非负的情况,在网络路由、地图导航等领域有着广泛的应用[^2]。 ### 工作原理 核心思想是从起始节点出发逐步探索近邻接点并更新距离直到访问到目标顶点为止;每次从未处理过的结点集合里挑选当前已知离起点近的一个作为新的考察对象,并据此调整其他未定节点的距离估计值直至遍历完成整个图结构。 具体来说: - 初始化阶段设定初始节点S至各目的节点V_i(i=0,1,...n)之间的临时短路径长度d[V_i]=∞(除了自身外),并将所有顶点标记为未确认状态; - 将起点加入优先队列Q中准备参与后续迭代运算过程; - 当前轮次内选取具有小代价评估函数f(n)=g(n)+h(n)(这里特指仅考虑实际开销即令启发式项h≡0情形下简化版A*搜索策略也就是纯粹基于累积耗费度量标准来决定先后顺序) 的候选项u∈Q执行扩展操作——对于每一个与之相连且尚未被终确定下来的邻居v而言: - 如果通过u到达v的新测得总成本lower than 原先记录下的预估值,则采用这条更优路线替换旧方案并相应修改关联属性字段parent[v]:=u以及dist[v]:=alt; - 循环上述流程不断重复直至找到终点t或者待检视列表为空表示不存在可行解结束程序运行。 ### C语言实现示例 下面给出一段简单的C语言代码实现了基本功能框架: ```c #include <stdio.h> #include <limits.h> #define V 9 // Number of vertices in the graph // A utility function to find the vertex with minimum distance value, // from the set of vertices not yet included in shortest path tree. int minDistance(int dist[], int sptSet[]) { // Initialize min value int min = INT_MAX, min_index; for (int v = 0; v < V; v++) if (sptSet[v] == 0 && dist[v] <= min) min = dist[v], min_index = v; return min_index; } void printSolution(int dist[]) { printf("Vertex \t\t Distance from Source\n"); for (int i = 0; i < V; i++) printf("%d \t\t %d\n", i, dist[i]); } void dijkstra(int graph[V][V], int src) { int dist[V]; // The output array. dist[i] will hold the shortest // distance from src to i. bool sptSet[V]; // sptSet[i] will be true if vertex i is included in shortest // path tree or shortest distance from src to i is finalized. // Initialize all distances as INFINITE and stpSet[] as false for (int i = 0; i < V; i++) dist[i] = INT_MAX, sptSet[i] = false; // Distance of source vertex from itself is always 0 dist[src] = 0; // Find shortest path for all vertices for (int count = 0; count < V - 1; count++) { // Pick the minimum distance vertex from the set of vertices not // yet processed. u is always equal to src in first iteration. int u = minDistance(dist, sptSet); // Mark the picked vertex as processed sptSet[u] = true; // Update dist value of the adjacent vertices of the picked vertex. for (int v = 0; v < V; v++) // Update dist[v] only if it's not in sptSet, there is an edge from // u to v, and total weight of path from src to v through u is smaller // than current value of dist[v] if (!sptSet[v] && graph[u][v] && dist[u] != INT_MAX && dist[u] + graph[u][v] < dist[v]) dist[v] = dist[u] + graph[u][v]; } // Print the constructed distance array printSolution(dist); } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值