Dijkstra算法

Dijkstra算法是一种用于在加权图中寻找单源最短路径的算法。它由荷兰计算机科学家Edsger Dijkstra在1956年提出。

该算法基于贪心策略,通过不断选择当前最短路径上的顶点来逐步确定最短路径。它使用一个距离数组来记录起始点到每个顶点的距离,并使用一个集合来存储已经求得最短路径的顶点。

Dijkstra算法的步骤如下:

1. 初始化距离数组,将起始点的距离设置为0,将其他点的距离设置为无穷大。
2. 将起始点加入集合中。
3. 对集合中的每个顶点,计算其到未访问顶点的距离,并更新距离数组。
4. 选择距离数组中值最小的顶点作为下一个要访问的顶点,并将其从集合中移除。
5. 重复步骤3和步骤4,直到集合为空。
6. 返回最终的距离数组。

Dijkstra算法的特点是能够处理边权值为正的有向图或无向图。它的时间复杂度为O(V^2),其中V为顶点的数量。在使用最小堆等数据结构优化后,可以将时间复杂度降低到O((V+E)logV),其中E为边的数量。

总结来说,Dijkstra算法是一种求解单源最短路径问题的有效算法,它通过贪心策略不断选择当前最短路径上的顶点来逐步确定最短路径。

Dijkstra算法是一种用于找到图中从一个顶点到其他所有顶点的最短路径的算法。它具有以下优点和缺点:

优点:
1. 算法确保找到所有的最短路径:Dijkstra算法能够找到从起始顶点到所有其他顶点的最短路径,并且保证这些路径是实际的最短路径。
2. 算法适用于有向和无向图:Dijkstra算法可以用于有向图和无向图,可以处理复杂的图结构。
3. 算法的时间复杂度较低:在使用适当的数据结构(如最小堆)和优化技巧(如提前终止)的情况下,Dijkstra算法的时间复杂度可以降低到O((V+E)logV),其中V是顶点数,E是边数。

缺点:
1. 算法不适用于大规模图:当图非常大时,Dijkstra算法的性能可能会下降,因为需要对所有的节点进行扫描和更新。
2. 算法需要额外的空间:Dijkstra算法需要使用额外的数据结构(如距离数组和前驱数组)来存储每个顶点的最短路径和前驱顶点,因此需要额外的空间来存储这些信息。
3. 算法依赖于边权重非负:Dijkstra算法的前提是边的权重必须是非负的,否则算法可能会产生错误的结果。如果边的权重存在负值,应该使用其他算法(如贝尔曼-福特算法)。

下面是实现Dijkstra算法的代码

#include <bits/stdc++.h>
#define ll long long
#define endl "\n"
#define KUI ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
using namespace std;
struct jgt
{
    int go;
    int d;
};
const int con = 1e5 + 4;
int n, m, k;
bool vis[con];
int dis[con];
void take()
{
    cin >> n >> m;
    memset(dis, 127, sizeof dis); // 将dis赋值为较大数;
    vector<struct jgt> v[n + 1];
    int a1;
    struct jgt ans;
    for (int i = 1; i <= m; i++)
    {
        cin >> a1 >> ans.go >> ans.d;
        v[a1].push_back(ans); // 存图路径;
    }
    dis[1] = 0; // 1为根节点,距离为0;
    for (int i = 1; i <= n; i++)
    {
        k = 0;
        // 寻找未走过的距离最短的节点;
        for (int j = 1; j <= n; j++)
        {
            if (vis[j] == 0 && dis[j] < dis[k])
            {
                k = j;
            }
        }
        // 走最短点,标记为1;
        vis[k] = 1;
        // 更新路径;
        for (auto &x : v[k])
        {
            if (dis[x.go] > dis[k] + x.d)
            {
                dis[x.go] = dis[k] + x.d;
            }
        }
    }
    for (int i = 1; i <= n; i++)
    {
        cout << dis[i] << endl;
    }
}
int main()
{
    KUI;
    int t1 = 1;
    // cin >> t1;
    while (t1--)
    {
        take();
    }
    return 0;
}

利用优先队列来优化算法

#include <bits/stdc++.h>
#define ll long long
#define endl "\n"
#define KUI ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
using namespace std;
struct jgt
{
    int go;
    int d;
};
struct jgt2
{
    int po;
    int d;
    friend bool operator<(struct jgt2 a, struct jgt2 b)
    {
        if (a.d != b.d)
        {
            return a.d > b.d; // 如果距离不一样,就把距离短的排前面;
        }
        else
        {
            return a.po > b.po; // 如果距离不样,就把节点数较小的排前面;
        }
    }
};
const int con = 1e5 + 4;
int n, m, k;
bool vis[con];
int dis[con];
vector<struct jgt> v[con];
priority_queue<struct jgt2> pq;
void Dijkstra()
{
    dis[1] = 0; // 根节点赋值距离为0;
    struct jgt2 ans;
    ans.po = 1;
    ans.d = 0;
    pq.push(ans); // 根节点入队;
    while (pq.size() > 0)
    {
        ans = pq.top(); // 取距离最短的节点;
        pq.pop();
        if (vis[ans.po] == 1) // 如果该节点已经出队过(在这之前出队,表示该节点的距离更短),那么继续找下一个节点;
        {
            continue;
        }
        vis[ans.po] = 1; // 标记走过该节点;
        struct jgt2 ans2;
        for (auto &x : v[ans.po])
        {
            if (dis[x.go] > dis[ans.po] + x.d) // 从该节点出发到该节点距离更短,就入队该节点;
            {
                dis[x.go] = dis[ans.po] + x.d;
                ans2.po = x.go;
                ans2.d = dis[x.go];
                pq.push(ans2); // 入队不要限制,因为要取最短路径,要尽可能把节点入队,这样优先队列可以取到最小距离;
            }
        }
    }
}
void take()
{
    cin >> n >> m;
    memset(dis, 127, sizeof dis); // 将dis赋值为较大数;
    int a1;
    struct jgt ans;
    for (int i = 1; i <= m; i++)
    {
        cin >> a1 >> ans.go >> ans.d;
        v[a1].push_back(ans); // 存图路径;
    }
    Dijkstra();
    for (int i = 1; i <= n; i++)
    {
        cout << dis[i] << endl;
    }
}
int main()
{
    KUI;
    int t1 = 1;
    // cin >> t1;
    while (t1--)
    {
        take();
    }
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值