[实验]贪心算法之单元最短路径问题 基于C++

一、 实验内容:

给定带权有向图G=(V,E),其中每条边的权都是非负数。给定一个起始顶点,称为源。计算从源到所有其他定点的最短路径长度,路径长度是各边权重之和。该问题称为单源最短路径问题。
基本思想:Dijkstra算法(迪杰斯特拉算法)是解单源最短路径问题的贪心算法。
算法思路:
1、选一顶点v为源点,并视从源点v出发的所有边为到各顶点的最短路径(确定数据结构:因为求的是最短路径,所以①就要用一个记录从源点v到其它各顶点的路径长度数组dist[],开始时,dist是源点v到顶点i的直接边长度,即dist中记录的是邻接阵的第v行。②设一个用来记录从源点到其它顶点的路径数组path[],path中存放路径上第i个顶点的前驱顶点)。
2、在上述的最短路径dist[]中选一条最短的,并将其终点(即<v,k>)k加入到集合s中。
3、调整T中各顶点到源点v的最短路径。 因为当顶点k加入到集合s中后,源点v到T中剩余的其它顶点j就又增加了经过顶点k到达j的路径,这条路径可能要比源点v到j原来的最短的还要短。调整方法是比较dist[k]+g[k,j]与dist[j],取其中的较小者。
4、再选出一个到源点v路径长度最小的顶点k,从T中删去后加入S中,再回去到第三步,如此重复,直到集合S中的包含图G的所有顶点。

二、 实验结果

在这里插入图片描述

三、实验分析与结论

定义源点为 0,dist[i]为源点 0 到顶点i的最短路径。其过程描述如下:
步骤 dist[1] dist[2] dist[3] dist[4] 已找到的集合
第1步 8 1 2 +∞ { 2 }
第2步 8 × 2 4 { 2, 3 }
第3步 5 × × 4 { 2, 3, 4 }
第4步 5 × × × { 2, 3, 4, 1 }
第5步 × × × × { 2, 3, 4, 1 }
Dijkstra 算法(中文名:迪杰斯特拉算法)是由荷兰计算机科学家 Edsger Wybe Dijkstra 提出。该算法常用于路由算法或者作为其他图算法的一个子模块。举例来说,如果图中的顶点表示城市,而边上的权重表示城市间开车行经的距离,该算法可以用来找到两个城市之间的最短路径。

四、源代码:

#include "stdafx.h"
#include <iostream>

using namespace std;

int  matrix[100][100]; // 邻接矩阵
bool visited[100];     // 标记数组
int  dist[100];        // 源点到顶点 i 的最短距离
int  path[100];        // 记录最短路的路径
int  source;           // 源点
int  vertex_num;       // 顶点数
int  edge_num;         // 边数

void Dijkstra(int source)
{
    memset(visited, 0, sizeof(visited));  // 初始化标记数组
    visited[source] = true;
    for (int i = 0; i < vertex_num; i++)
    {
        dist[i] = matrix[source][i];
        path[i] = source;
    }

    int min_cost;        // 权值最小
    int min_cost_index;  // 权值最小的下标

    for (int i = 1; i < vertex_num; i++)  // 找到源点到另外 vertex_num-1 个点的最短路径
    {
        min_cost = INT_MAX;

        for (int j = 0; j < vertex_num; j++)
        {
            if (visited[j] == false && dist[j] < min_cost)  // 找到权值最小
            {
                min_cost = dist[j];
                min_cost_index = j;
            }
        }

        visited[min_cost_index] = true;  // 该点已找到,进行标记

        for (int j = 0; j < vertex_num; j++)  // 更新 dist 数组
        {
            if (visited[j] == false &&
                matrix[min_cost_index][j] != INT_MAX &&  // 确保两点之间有边
                matrix[min_cost_index][j] + min_cost < dist[j])
            {
                dist[j] = matrix[min_cost_index][j] + min_cost;
                path[j] = min_cost_index;
            }
        }
    }
}

int main()
{
    cout << "请输入图的顶点数(<100):";
    cin >> vertex_num;
    cout << "请输入图的边数:";
    cin >> edge_num;

    for (int i = 0; i < vertex_num; i++)
        for (int j = 0; j < vertex_num; j++)
            matrix[i][j] = (i != j) ? INT_MAX : 0;  // 初始化 matrix 数组

    cout << "请输入边的信息(点 点 权):\n";
    int u, v, w;//w:权
    for (int i = 0; i < edge_num; i++)
    {
        cin >> u >> v >> w;
        matrix[u][v] = matrix[v][u] = w;
    }

    cout << "请输入源点(<" << vertex_num << "):";
    cin >> source;
    Dijkstra(source);

    for (int i = 0; i < vertex_num; i++)
    {
        if (i != source)
        {
            cout << source << " 到 " << i << " 的最短距离是:" << dist[i] << ",路径是:" << i;
            int t = path[i];
            while (t != source)
            {
                cout << "--" << t;
                t = path[t];
            }
            cout << "--" << source << endl;
        }
    }

    return 0;
}

单源最短路径问题可以使用基于贪心算法的Dijkstra算法来解决。下面是解决该问题的步骤: 1. 初始化:将源点到所有其他点的距离初始化为无穷大,将源点到自身的距离初始化为0。 2. 选择:从未确定最短路径的点中选择距离最短的点作为当前点。 3. 更新:更新当前点的邻居节点的距离,如果从源点到当前点的距离加上当前点到邻居节点的距离小于源点到邻居节点的距离,则更新源点到邻居节点的距离。 4. 标记:将当前点标记为已确定最短路径的点。 5. 重复:重复2-4步骤,直到所有点都被标记为已确定最短路径的点。 下面是使用C++实现Dijkstra算法代码: ```c++ #include <iostream> #include <vector> #include <queue> #include <limits.h> using namespace std; typedef pair<int, int> PII; const int N = 100010; int h[N], e[N], w[N], ne[N], idx; int dist[N]; bool st[N]; int n, m; void add(int a, int b, int c) { e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++ ; } void dijkstra() { memset(dist, 0x3f, sizeof dist); dist[1] = 0; priority_queue<PII, vector<PII>, greater<PII>> q; q.push({0, 1}); while (q.size()) { auto t = q.top(); q.pop(); int ver = t.second, distance = t.first; if (st[ver]) continue; st[ver] = true; for (int i = h[ver]; ~i; i = ne[i]) { int j = e[i]; if (dist[j] > distance + w[i]) { dist[j] = distance + w[i]; q.push({dist[j], j}); } } } } int main() { cin >> n >> m; memset(h, -1, sizeof h); while (m -- ) { int a, b, c; cin >> a >> b >> c; add(a, b, c); } dijkstra(); if (dist[n] == 0x3f3f3f3f) puts("-1"); else cout << dist[n] << endl; return 0; } ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值