迪杰斯特拉算法反思(C++)

Dijkstra算法是用于求解单源(一个起点)最短路径(距离或路径方案)的经典算法。注意:这里所有路径的距离必须非负,否则不能用迪杰斯特拉算法。

从该算法中,我感悟到编程的思想,或者说,解决问题的思想,就是要一步一步来,确定好要做的事情,和做事的顺序,从而少做无用功(或者说本可以省去的活),这里的关键是我们要找到问题各个对象之间隐含的关系(如最典型的关系:可递推或其他)。如在一个图(无向图或者有向图)中求解从一点s到其他各点的最短路径时,就可以先看从该点直接可达的点之间的距离,选择距离最近的点,设为t1。该点t1一定是最终状态,也就是说,从s到达t1的最短路径距离一定是刚才确定的距离。因为再找其他的中间点到达t1一定不可能比这个更小了。(前面已经说过t1是直接可达的点里最近的点了,不妨假设一个中间点u,从s到u再到t1可达,那么从s到u就已经大于等于前面直接从s到t1的距离了,何况还要再加上一个u到t1的距离(非负)。因此,t1是确定的一个s到t1的最短距离的点了)然后以t1为中间点去更新其他还未确定最短路径的点,接着选取距离最短的点,依次类推...直到确定从源点达到所有点的最短路径。

那么,如何用代码描述呢?也就是如何写代码呢?先来理一下代码的主体思路,我们需要确定n个点的最短路径,因此外层循环n次,对循环内,每次选取一个距离最近的点作为中间点是一步,下一步还要以该中间点更新其他还未确定的从源点到各点的最短距离。所以,整体思路就是,外层循环处理n个点,然后里面有两步,分别是,选中间点和更新其他各点距离。

那么需要什么数据结构呢?如何记录一个点是否已经确定了最短路径呢?使用一个bool型的数组vis[]记录即可。如何记录一个点确定的最短路径距离呢?使用用int型的数组dis[]记录即可。其中两个数组的下标对应图中各点的编号。

//初始时dis[]数组中的距离设为INF
void Dijkstra(int s){
    dis[s] = 0;
    for(int i=0; i<n; i++){ //外层循环
        
        //下面为循环内的第一步,选中间点
        int u=-1;
        int minv = INF;
        for(int j=0; j<n; i++){
            if(vis[j] == false && dis[j] < minv){
                minv = dis[j];
                u = j;
            }
        }
        if(u == -1) return;
        vis[u] == true;
        //下面为循环内的第二步,更新其他点的距离
        for(int k=0; k<adj[u].size(); k++){
            edge tempv = adj[u][k];
            if(vis[tempv.v] == false && dis[u] + tempv.w < dis[tempv]){
                dis[tempv] = dis[u] + tempv.w;
            }
        }
    }
}

简言之,迪杰斯特拉算法的关键就是明白,各个击破的道理,知道:找到从源点直接可达的所有点中距离最短的那个点和相应距离,它一定是整个图中从源点到那个点的最短路径解,从而击破一个点(,然后从源点到其他各点的路径可由前面确定了最短路径的点传递过来得到最短路径,再接着一个一个击破其他点。)

再强调一下,充分利用隐含关系往往是更高效地解决问题的关键。

  • 18
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是C++实现Dijkstra算法的代码示例: ```cpp #include <iostream> #include <vector> #include <queue> #include <climits> using namespace std; const int INF = INT_MAX; // 无穷大 // 边的结构体 struct Edge { int to; // 目标节点 int weight; // 权重 }; // 图的结构体 struct Graph { int V; // 节点数 vector<vector<Edge>> adj; // 邻接表 Graph(int V) { this->V = V; adj.resize(V); } // 添加边 void addEdge(int u, int v, int weight) { Edge edge; edge.to = v; edge.weight = weight; adj[u].push_back(edge); } // Dijkstra算法 vector<int> dijkstra(int start) { vector<int> dist(V, INF); // 存储最短距离 dist[start] = 0; // 起始节点到自身的距离为0 // 创建优先队列,按照距离从小到大排序 priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq; pq.push(make_pair(0, start)); while (!pq.empty()) { int u = pq.top().second; pq.pop(); // 遍历u的所有邻接节点 for (const Edge& edge : adj[u]) { int v = edge.to; int weight = edge.weight; // 如果经过u到v的距离更短,则更新最短距离 if (dist[u] + weight < dist[v]) { dist[v] = dist[u] + weight; pq.push(make_pair(dist[v], v)); } } } return dist; } }; int main() { int V, E; cin >> V >> E; // 输入节点数和边数 Graph graph(V); // 输入边的信息 for (int i = 0; i < E; i++) { int u, v, weight; cin >> u >> v >> weight; graph.addEdge(u, v, weight); } int start; cin >> start; // 输入起始节点 vector<int> dist = graph.dijkstra(start); // 调用Dijkstra算法 // 输出最短距离 for (int i = 0; i < V; i++) { cout << "最短距离[" << start << "][" << i << "] = " << dist[i] << endl; } return 0; } ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值