【ACWing】849. Dijkstra求最短路 I

题目地址:

https://www.acwing.com/problem/content/851/

给定一个 n n n个点 m m m条边的有向图,可能存在重边和自环,无负权边。求 1 1 1号点到 n n n号点的最短距离。如果不存在路径,则输出 − 1 -1 1

输入格式:
第一行包含整数 n n n m m m。接下来 m m m行每行包含三个整数 x x x y y y z z z,表示存在一条从点 x x x到点 y y y的有向边,边长为 z z z

输出格式:
输出一个整数,表示 1 1 1号点到 n n n号点的最短距离。如果路径不存在,则输出 − 1 -1 1

数据范围:
1 ≤ n ≤ 500 1\le n\le 500 1n500
1 ≤ m ≤ 1 0 5 1\le m\le 10^5 1m105
e ≤ 10000 e\le 10000 e10000
e e e为边长

由数据范围知道这个图是个稠密图,所以要用朴素版Dijkstra算法来做(意思是,求距离源点最近的点的时候,要用循环的方式找到)。具体算法是这样的,首先开两个数组,一个int数组存各个点到 1 1 1号点的最短距离,另一个bool数组存 1 1 1号点到各个点的最短路是否已经被求出。显然 1 1 1号点自己的最短路是 0 0 0,已经求出了(注意,即使它的最短路确实已经确定了,但是这个时候不要标记其最短路已经求出,因为我们还要靠它来更新其余点最短路距离。具体看代码),接下来进行 n n n次循环,每次新求出某个点到 1 1 1号点的最短路。在每次循环里,首先找到未确定最短路的点中,最短路最短的那个点(第一轮循环会找到源点。这就是为什么一开始不要标记源点为已求出),然后标记其为已求出,再用它以及它到各个点的距离(这个距离存在邻接矩阵里了),来更新所有未求出最短路的点。这样每次循环都能求出一个点的最短路,循环 n n n次就求出来源点到所有点的最短路了。当然中途如果提前求出了第 n n n号点的最短路,可以直接退出循环。代码如下:

#include <iostream>
#include <cstring>
using namespace std;

const int N = 510, INF = 0x3f3f3f3f;
int n, m;
int g[N][N], dist[N];
bool st[N];

int dijkstra() {
  memset(dist, 0x3f, sizeof dist);
  dist[1] = 0;

  for (int i = 0; i < n; i++) {
    int t = -1;
    for (int j = 1; j <= n; j++)
      if (!st[j] && (t == -1 || dist[t] > dist[j])) t = j;

    if (t == n) break;

    st[t] = true;
    for (int j = 1; j <= n; j++)
      if (!st[j]) dist[j] = min(dist[j], dist[t] + g[t][j]);
  }

  return dist[n] == INF ? -1 : dist[n];
}

int main() {
  cin >> n >> m;

  memset(g, 0x3f, sizeof g);

  while (m--) {
    int a, b, c;
    cin >> a >> b >> c;
    if (a == b) g[a][b] = 0;
    else g[a][b] = min(g[a][b], c);
  }

  cout << dijkstra() << endl;
}

时空复杂度 O ( n 2 ) O(n^2) O(n2)

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值