Dijkstra最短路算法

之前在比赛中用到了dijkstra最短路算法, 用于计算一个顶点到其他节点的最短距离和路径.
以起点为源点,向外扩展的方式,搜寻当前步骤下能找到的最短距离.

思想

贪心:找到该点到所有点的最短路径

  1. 俩个集合, 一个(dis)是源点到当前该点的最短路径,一个(visited)是源点到该点是否已经找到最短路径
  2. 初始时设定dis[] = INT_MAX, dis[start] = 0,后续需要比较是否可以找到比当前dis[i]小的值
  3. 每轮循环分别找到当前未被访问的点中到源点最短距离的点,加入visited集合中
  4. 每轮循环更新dis集合,根据确定的minpos,找到未被访问的点,且小于dis[minpos]+adj[minpos][i]时更新;
由于minpos的前一节点的邻接节点可能未被访问完,但是我们还是只当dis[i] < dis[minpos]+adj[minpos][i]时才会更新dis[i],然后在下一轮确定对应的minpos,然后继续查找,当visited[end]==true时,end节点已被查找到,可以结束查找.
#include <iostream>
#include <vector>
#include <limits.h>
#include <algorithm>
using namespace std;

// 邻接矩阵-无向图
// adj[i][j] == 0 表示 i j 不相邻
vector<vector<int>> adj = {
    {0,1,6,3,0}, 
    {1,0,7,1,2},
    {6,7,0,2,0},
    {3,1,2,0,7},
    {0,2,0,7,0}
};

// 基于邻接矩阵dijkstra求解最短路
int dijkstra(vector<vector<int>> adj, int& start, int& end, vector<int>&path)
{
    int n = adj.size();
    if(start >= n || start < 0 || end >= n || end < 0)
        return -1;
    vector<int> dis(n, INT_MAX);    // 当前点到源点的最短距离
    vector<bool> visited(n, false); // 访问集合
    vector<int> pre(n, -1);       // 当前点最短路径的前一节点

    dis[start] = 0;                 // 保证初始查找点为源点start
    pre[start] = start;          // 设置源点的prepos为start

    for(;;)
    {
        int mindis = INT_MAX;
        int minpos = -1;

        // 找到本轮查找的初始点
        for(int i = 0; i < n; ++i)
        {
            if(!visited[i] && dis[i] < mindis)
            {
                mindis = dis[i];
                minpos = i;
            }
        }
        // 不存在邻接路径
        if(minpos == -1)
            break;
        visited[minpos] = true;
        // 如果终点在确认集合中,则退出查找,保存路径
        if(visited[end])
        {
            int tmp = end;
            path.push_back(end);
            while(pre[tmp] != start && pre[tmp] != -1)
            {
                path.push_back(pre[tmp]);
                tmp = pre[tmp];
            }
            path.push_back(start);
            reverse(path.begin(), path.end());
            break;
        }
        for(int j = 0; j < n; ++j)
        {
            if(!visited[j] && adj[minpos][j] > 0)
            {
                if(dis[j] > dis[minpos] + adj[minpos][j])
                {
                    dis[j] = dis[minpos] + adj[minpos][j];
                    pre[j] = minpos;
                }
            }
        }
    }

    return dis[end];
}

void printpath(vector<int>&path)
{
        // 打印路径
    for(int i = 0; i < path.size(); ++i)
    {
        if(i != path.size()-1)
        {
            cout << path[i]+1 <<"->";
        }
        else
        {
            cout << path[i]+1;
        }
    }      
    cout << endl;
}
int main()
{
    int start, end;
    cin >> start >> end;
    vector<int> path;
    int mindis = dijkstra(adj, start, end, path);
    cout << mindis << endl;
    printpath(path);
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值