最短路
朴素Dijkstra
链接
1、思路
*0、定义数组 dis[n]
(从1到其它点的距离), s[n]
(已经确定最短距离的点);
*1、初始化 dis[1] = 0
, dis[其它点] = 正无穷;
*2、 for(1 ~ n);——————————循环 n 次,更新所有的点 t;
*3 找到 不在s中的,距离最近的点 t;
*4 将t加入s;
*5 用t更新其它点的距离;————————循环n次
(这里是两 层 循环, 所以时间复杂度是 n^2)
*6 返回
例题
#include<bits/stdc++.h>
using namespace std;
const int N = 510;
int n, m;
int g[N][N];
int djs[N];
bool s[N];
int djst(){
memset(djs, 0x3f3f3f3f, sizeof djs); /* *1 */
djs[1] = 0; /* *1 */
for(int i = 0; i < n; i ++){ /* *2 */
int t = -1; /* *3 */
for(int j = 1; j <= n; j ++) /* *3 */
if(!s[j] && (t == -1 || djs[t] > djs[j])) /* *3 */
t = j; /* *3 */
s[t] = 1; /* *4 */
for(int j = 1; j <= n; j ++) /* *5 */
djs[j] = min(djs[j], djs[t] + g[t][j]); /* *5 */
}
if(djs[n] == 0x3f3f3f3f) return -1; /* *6 */
return djs[n]; /* *6 */
}
int main(){
cin >> n >> m;
memset(g, 0x3f3f3f3f, sizeof g);
while(m --){
int a, b, c;
cin >> a >>b >>c;
g[a][b] = min(g[a][b], c);
}
int t = djst();
cout << t;
return 0;
}
/*
0x3f3f3f3f 代表 正无穷。
*/
优化Dijkstra :
题目链接
优先队列的函数补充:
优先队列数据结构(堆)的函数用法 20.10.17
可以更新的地方:
分析:
*2、 for(1 ~ n);·;
*3 找到 不在s中的,距离最近的点 t;——————*2、*3共循环 n^2 次来找点 t;(用小根堆堆来做可时间O(n))
,也就是用优先队列,优化后为O(log n)
就是这里可以优化
for(int j = 1; j <= n; j ++) /* *3 */
if(!s[j] && (t == -1 || djs[t] > djs[j])) /* *3 */
t = j;
*4 将t加入s; ——————————————————这里是n次
*5 用t更新其它点的距离; —————————————具体操作时m次,遍历所有的边来更新
堆优化后 整个计算量最大是 O(m log n)。
堆的写法:
手写或用优先队列,两者时间是一个级别的,用优先队列,不需要手写堆。
#include<bits/stdc++.h>
using namespace std;
const int N = 150010;
int n, m;
int djs[N];
bool st[N];
int ne[N], e[N], h[N], w[N], idx = 0;
typedef pair<int ,int> P;//距离1的距离,以及点号, 这里默认是按照第一个元素来排序的
void add(int a, int b, int c){
e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++;
}
int djst(){
memset(djs, 0x3f, sizeof djs);
djs[1] = 0;
priority_queue< P, vector<P>, greater<P> > heap;/* *1 */
heap.push( {0, 1} );
while(heap.size()){
auto t = heap.top();
heap.pop();
int ver = t.second, distance = t.first;
if(st[ver]) continue;
st[ver] = 1; /* *2 */
for(int i = h[ver]; i != -1; i = ne[i]){
int j = e[i];
if(djs[j] > distance + w[i]){
djs[j] = distance + w[i];
heap.push({djs[j], j});
}
}
}
if(djs[n] == 0x3f3f3f3f) return -1;
return djs[n];
}
int main(){
cin >> n >> m;
memset(h, -1, sizeof h);
while(m --){
int a, b, c;
cin >> a >>b >>c;
add(a, b, c);
}
cout << djst() << endl;
return 0;
}
给定一个n个点m条边的有向图,图中可能存在重边和自环,所有边权均为非负值。
请你求出1号点到n号点的最短距离,如果无法从1号点走到n号点,则输出-1。
输入格式
第一行包含整数n和m。
接下来m行每行包含三个整数x,y,z,表示存在一条从点x到点y的有向边,边长为z。
输出格式
输出一个整数,表示1号点到n号点的最短距离。
如果路径不存在,则输出-1。
数据范围
1≤n,m≤1.5×105,
图中涉及边长均不小于0,且不超过10000。
输入样例:
3 3
1 2 2
2 3 1
1 3 4
输出样例:
3
*1 强调:“>”不要两个拼在一起。
less是从大到小,greater是从小到大。
第一个参数为数据类型。
第二个参数为容器类型。
第三个参数为比较函数。
*2 千万不要忘记。