Dijkstra算法

Dijkstra算法

用途

用于解决单源最短路径问题,即在给定图和起始结点的基础上,求所有其他结点到起始结点的最短路径。

算法描述

  1. 创建集合S用来存放已访问结点,集合D用来存放所有结点到起始结点的最短路径;
  2. 从D中找到值最小的结点i(即起始结点能到达的未访问结点中路径最短的那个),将其并入S;
  3. 以i为新的接入点,遍历所有未访问结点,如果存在结点j到i的距离加上起始结点到i的距离小于起始结点直接到j的距离,则更新起始结点到j的最短距离D[j];
  4. 重复 2-3步,直到访问完所有与起始结点连通的结点。

如果要将具体的最短路径输出,只要在每次更新最短距离时保存待更新结点的前驱结点即可。

代码实现——邻接矩阵

const int maxn = 1000;
const int INF = 1000000000;

int g[maxn][maxn], n;        // 邻接矩阵,结点个数
bool visit[maxn];               // 判断结点是否已访问
int d[maxn];                    // 存储第i个结点到起始结点的距离
int pre[maxn];                  // 记录从起点到顶点v的最短路径上v的前驱结点

void Dijkstra(int s)
{
    for (int i = 0; i < n; i++)     // 初始化
    {
        visit[i] = false;
        d[i] = INF;
        pre[i] = i;
    }
    d[s] = 0;       // 到自身的距离为0
    
    for (int i = 0; i < n; i++)
    {
        int u = -1, minD = INF;     // 分别存放到s距离最小的结点下标和距离
        for (int j = 0; j < n; j++)     // 遍历所有结点,找到离s最近的结点
        {
            if (visit[j] == false && d[j] < minD)
            {
                u = j;
                minD = d[j];
            }
        }
        
        if (u == -1)        // 不存在最近结点,即s与所有未访问结点都不连通
            return;
        visit[u] = true;    // 找到最近结点,并标记已访问
        
        for (int v = 0; v < n; v++)     // 以u结点为新的接入点,更新未访问结点到起点的最小距离
        {
            // 更新距离要满足:该结点与u结点连通;未访问;以u为接入点比直接与起始结点相连更近
            if (g[u][v] < INF && visit[v] == false && d[u] + g[u][v] < d[v])    
            {
                d[v] = d[u] + g[u][v];
                pre[v] = u;
            }
        }
    }
}

代码实现——邻接表

const int maxn = 1000;
const int INF = 1000000000;

struct node
{
    int v,l;        // v结点编号,l边权
};

vector<node> adj[maxn];        // 邻接表
int n;                          // 结点个数
int d[maxn];                    // 存储第i个结点到起始结点的距离
bool visit[maxn];               // 判断结点是否已访问       
int pre[maxn];                  // 记录从起点到顶点v的最短路径上v的前驱结点

void Dijkstra(int s)
{
    for (int i = 0; i < n; i++)     // 初始化
    {
        visit[i] = false;
        d[i] = INF;
        pre[i] = i;
    }
    d[s] = 0;       // 到自身的距离为0
    
    for (int i = 0; i < n; i++)
    {
        int u = -1, minD = INF;     // 分别存放到s距离最小的结点下标和距离
        for (int j = 0; j < n; j++)     // 遍历所有结点,找到离s最近的结点
        {
            if (visit[j] == false && d[j] < minD)
            {
                u = j;
                minD = d[j];
            }
        }
        
        if (u == -1)        // 不存在最近结点,即s与所有未访问结点都不连通
            return;
        visit[u] = true;    // 找到最近结点,并标记已访问
        
        for (int j = 0; j < adj[u].size(); j++)     // 以u结点为新的接入点,更新未访问结点到起点的最小距离
        {
            int v = adj[u][j].v;       // 结点编号
            int l = adj[u][j].l;       // 距离
            // 更新距离要满足:该结点与u结点连通;未访问;以u为接入点比直接与起始结点相连更近
            if (visit[v] == false && d[u] + l < d[v])    
            {
                d[v] = d[u] + l;
                pre[v] = u;
            }
        }
    }
}

输出最短路径,只要递归输出pre数组即可

void DFS(int s, int now)        // s为起始结点,now为当前访问结点
{
    if (s == now)
    {
        printf("%d", s);
        return;
    }
    
    DFS(s, pre[now]);
    printf("%d", now);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值