Dijkstra算法的简单应用

这里讲一下Dijkstra算法在无向图中的简单使用.

下面给出一个无向图的示例:

要求出从V0到各个点的最短距离,可以使用Dijkstra算法(各边权值必须为正)。

具体地,我们讲解一下从V0到V5的最短路径。

首先找到从V0到V1和V2的距离,分别为5和3,去其中最短,并更新节点为节点2。

接着找与节点2相邻但是未访问过的节点(即V1,V3,V4),找出其中最短的距离并和原来的距离作比较,(例如,从V0到v2再到v1和原来从v0到v1作比较)。去其中最小的值,并更新节点。

重复以上步骤,知道找到到达V5的最短路径。

见下面:

最后得到最短路径是10。

下面给出C++代码(从V0到各个节点的最短路径)

#include <iostream>
#include <limits>

#define INF numeric_limits<int>::max()

using namespace std;

// 定义无向图的节点数最大值
const int MAX_NODES = 100;

// Dijkstra算法求解最短路径
void dijkstra(int graph[MAX_NODES][MAX_NODES], int n, int start) 
{
    int distances[MAX_NODES]; // 存储到各个节点的最短距离
    bool visited[MAX_NODES]; // 标记节点是否已被访问

    // 初始化
    for (int i = 0; i < n; i++)
    {
        distances[i] = INF;
        visited[i] = false;
    }

    distances[start] = 0; // 起始节点到自身的距离为0

    for (int i = 0; i < n - 1; i++) 
    {
        // 选择距离最短的节点作为当前节点
        int curr = -1;
        
        for (int j = 0; j < n; j++) 
        {
            if (!visited[j] && (curr == -1 || distances[j] < distances[curr]))
            {
                curr = j;
            }
        }

        if (curr == -1) 
        {
            break; // 无法继续扩展无限大的节点
        }

        visited[curr] = true;

        // 更新从当前节点到其他未访问节点的距离
        for (int j = 0; j < n; j++)
        {
            if (!visited[j] && graph[curr][j] != INF) 
            {
                distances[j] = min(distances[j], distances[curr] + graph[curr][j]);
            }
        }
    }

    // 打印最短距离
    for (int i = 0; i < n; i++) 
    {
        cout << "Distance from node " << start << " to " << i << ": ";
        if (distances[i] == INF) {
            cout << "uncontacted" << endl;
        }
        else {
            cout << distances[i] << endl;
        }
    }
}

int main() {
    int n = 6; // 图的节点数

    int graph[MAX_NODES][MAX_NODES] = 
    {
        {0, 5, 3, INF, INF, INF},
        {5, 0, 2, 6, INF, INF},
        {3, 2, 0, 7, 4, INF},
        {INF, 6, 7, 0, 1, 2},
        {INF, INF, 4, 1, 0, 6},
        {INF, INF, INF, 2, 6, 0}
    };

    int start = 0; // 起始节点

    dijkstra(graph, n, start);

    return 0;
}

运行结果:

当然可以把上述代码转换称为MATLAB语法

function:

function dijkstra(graph, n, start)
    INF = intmax('int32'); % 定义无穷大值
    
    distances = ones(n, 1, 'int32') * INF; % 存储到各个节点的最短距离
    visited = false(n, 1); % 标记节点是否已被访问

    % 初始化
    distances(start) = 0; % 起始节点到自身的距离为0

    for i = 1:(n-1)
        % 选择距离最短的节点作为当前节点
        curr = -1;
        
        for j = 1:n
            if ~visited(j) && (curr == -1 || distances(j) < distances(curr))
                curr = j;
            end
        end

        if curr == -1
            break; % 无法继续扩展无限大的节点
        end

        visited(curr) = true;

        % 更新从当前节点到其他未访问节点的距离
        for j = 1:n
            if ~visited(j) && graph(curr, j) ~= INF
                distances(j) = min(distances(j), distances(curr) + graph(curr, j));
            end
        end
    end

    % 打印最短距离
    for i = 1:n
        fprintf('Distance from node %d to %d: ', start, i);          
        if distances(i) == INF
            fprintf('uncontacted\n');
        else
            fprintf('%d\n', distances(i));
        end
    end
end

main:

n = 6; % 图的节点数
INF = intmax('int32');
graph = [
    0, 5, 3, INF, INF, INF;
    5, 0, 2, 6, INF, INF;
    3, 2, 0, 7, 4, INF;
    INF, 6, 7, 0, 1, 2;
    INF, INF, 4, 1, 0, 6;
    INF, INF, INF, 2, 6, 0
]; % 图的邻接矩阵

start = 1; % 起始节点(MATLAB的索引从1开始)

dijkstra(graph, n, start);

由于我们是直接转换成的MATLAB语法,但是需要注意一些事项:

matlab语法数组索引是从1开始的,所以我们的start要从1开始,最后的输出,也应将i-1改成i。

当然可以使用graphshortestpath()函数直接得到答案:

n = 6; % 图的节点数

graph = [
    0, 5, 3, inf, inf, inf;
    5, 0, 2, 6, inf, inf;
    3, 2, 0, 7, 4, inf;
    inf, 6, 7, 0, 1, 2;
    inf, inf, 4, 1, 0, 6;
    inf, inf, inf, 2, 6, 0
]; % 图的邻接矩阵

start = 1; % 起始节点(MATLAB的索引从1开始)
target = 6; % 目标节点(MATLAB的索引从1开始)
 
[dist,path,pred] = graphshortestpath(sparse(graph), start, target);

disp('最短路径为:');
disp(path);
disp('最短距离为:');
disp(dist);

以上便是此算法的一些简单的内容。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值