图论:最短路径算法
最短路:
最短路主要分为,单源最短路 和 多源汇最短路。
在单源最短路中要区分是否含有负权边,如果图中不含负权边使用主要算法有 dijkstra 算法,而含负权边则使用 bellman-ford 算法 或 spfa 算法。
在多源汇最短路中主要有 floyd 算法。
单源最短路:不含负权边、
朴素 dijkstra 算法
算法流程:假设存在 n 个点,m 条边,求 s 点到任意一点的最短距离
- 定义一个数组 dist,dist[i] 表示从 s 点到点 i 的距离。
- 初始化 dist,将 s 点初始化为 0,其余点初始化正无穷 (只要比图中任意一条边的权值都大,这个数不会影响到求解过程)
- 循环确定每个点到 s 的距离,因为 s 到 s 为 0,所以还剩 n - 1 个点需要确定,就循环 n - 1次。在每次循环中,
- 找到距离 s 最近的一个点,且这个点没有确定
- 用这个点去更新,其他点判断是否能使其它点到 s 的距离变短,如果能就将其更新,否则保持不变
- 一次循环结束时将这个点打上记号,表示当前点以确定
代码:
const int N = 1010;
int g[N][N]; // 使用邻接矩阵来存图
bool st[N]; // 标记:i 点是否已确定
int n;
void dijkstra(int s){
int dist[N];
// 初始化
memset(dist, 0x3f, sizeof dist);
dist[s] = 0;
for(int i = 0; i < n - 1; i ++) {
int t = -1;
for(int j = 1; j <= n; j++) {
if(!st[j] && (t == -1 || st[t] > st[j])) // 找到距离 s 最近的一个点,且这个点没有确定
t = j;
}
for(int j = 1; j <= n; j++) {
dist[j] = min(dist[j], dist[t] + g[t][j]); // 用这个点去更新,其他点判断是否能使其它点到 s 的距离变短,如果能就将其更新,否则保持不变
}
st[t] = true; // 一次循环结束时将这个点打上记号,表示当前点以确定
}
}
题目:P3371 【模板】单源最短路径(弱化版)
题目背景
本题测试数据为随机数据,在考试中可能会出现构造数据让SPFA不通过,如有需要请移步 P4779。
题目描述
如题,给出一个有向图,请输出从某一点出发到所有点的最短路径长度。
输入格式
第一行包含三个整数 n,m,sn,m,s,分别表示点的个数、有向边的个数、出发点的编号。
接下来 mm 行每行包含三个整数 u,v,wu,v,w,表示一条 u \to vu→v 的,长度为 ww 的边。
输出格式
输出一行 nn 个整数,第 ii 个表示 ss 到第 ii 个点的最短路径,若不能到达则输出 2^{31}-1231−1。
输入输出样例
输入 #1复制
4 6 1
1 2 2
2 3 2
2 4 1
1 3 5
3 4 3
1 4 4
输出 #1复制
0 2 4 3
说明/提示
【数据范围】
对于 20%20% 的数据:1\le n \le 51≤n≤5,1\le m \le 151≤m≤15;
对于 40%40% 的数据:1\le n \le 1001≤n≤100,1\le m \le 10^41≤