已解决
acwing算法基础之搜索与图论--spfa算法
来自网友在路上 171871提问 提问时间:2023-11-11 21:02:47阅读次数: 71
最佳答案 问答题库718位专家为你答疑解惑
目录
- 1 基础知识
- 2 模板
- 3 工程化
1 基础知识
存在负权边时,使用spfa算法来求解最短路问题,它的时间复杂度为O(m)。
spfa算法求最短路问题的关键步骤:
- 初始化距离数组dist为正无穷大,然后d[1] = 0。
- 定义队列q,将1号结点插入到队列中。
- 如果队列不空:弹出队头t,看看t能走到哪儿,比如t能走到x。如果dist[x] > dist[t] + edge[t][x],则更新dist[x],如果x不在队列中,则将x插入到队列q中。
- 继续执行步骤3,直到队列为空。
- dist[n],即为1号结点到n号结点的最短距离。如果等于0x3f3f3f3f,则表示不存在最短路,输出-1。
此外,spfa算法还可以用来判断图中是否存在负回环(额外维护一个cnt数组,表示1号结点到x号结点的最短路径上边的数目,如果cnt[x] >= n,则表示图中存在负回环)。
spfa算法判断图中是否存在负回环的关键步骤:
- 初始化cnt数组,将它们的值都设置为0。
- 定义队列q,将1号结点、2号结点、3号结点、…、n号结点插入到队列q中。
- 如果队列不空:弹出队头结点t,看看t能走到哪儿,比如t能走到x。如果dist[x] > dist[t] + edge[t][x],则更新dist[x]和cnt[x]。如果cnt[x] >= n,返回true,表示图存在负回环。如果x不在队列q中,则把x插入到队列中。
- 继续执行步骤3,直到队列为空。
- 返回false,表示图中不存在负回环。
2 模板
int n; // 总点数
int h[N], w[N], e[N], ne[N], idx; // 邻接表存储所有边
int dist[N]; // 存储每个点到1号点的最短距离
bool st[N]; // 存储每个点是否在队列中// 求1号点到n号点的最短路距离,如果从1号点无法走到n号点则返回-1
int spfa()
{memset(dist, 0x3f, sizeof dist);dist[1] = 0;queue<int> q;q.push(1);st[1] = true;while (q.size()){auto t = q.front();q.pop();st[t] = false;for (int i = h[t]; i != -1; i = ne[i]){int j = e[i];if (dist[j] > dist[t] + w[i]){dist[j] = dist[t] + w[i];if (!st[j]) // 如果队列中已存在j,则不需要将j重复插入{q.push(j);st[j] = true;}}}}if (dist[n] == 0x3f3f3f3f) return -1;return dist[n];
}
3 工程化
题目1:存在负权边,求最短路。
#include <iostream>
#include <cstring>
#include <queue>using namespace std;const int N = 1e5 + 10;
int n, m;
int dist[N];
bool st[N];
vector<vector<pair<int,int>>> g(N); //first表示能走到的结点,second表示这条边的长度void spfa() {memset(dist, 0x3f, sizeof dist);dist[1] = 0;queue<int> q;q.push(1);st[1] = true;while (!q.empty()) {int t = q.front();q.pop();st[t] = false;for (auto [x, w] : g[t]) {if (dist[x] > dist[t] + w) {dist[x] = dist[t] + w;if (!st[x]) {q.push(x);st[x] = true;}} }}if (dist[n] == 0x3f3f3f3f) cout << "impossible" << endl;else cout << dist[n] << endl;return;
}int main() {cin >> n >> m;int a, b, c;while (m--) {cin >> a >> b >> c;g[a].emplace_back(make_pair(b,c));}spfa();return 0;
}
题目2:判断图中是否存在负回环。
#include <iostream>
#include <cstring>
#include <vector>
#include <queue>using namespace std;const int N = 2010;
int n, m;
int dist[N], cnt[N];
bool st[N];
vector<vector<pair<int,int>>> g(N);//first表示下一个能走到的结点,second表示边的长度void spfa() {queue<int> q;//把n个结点都插入到队列q中for (int i = 1; i <= n; ++ i) {q.push(i);st[i] = true;}while (!q.empty()) {auto t = q.front();q.pop();st[t] = false;//看t能走到哪里for (auto [x, w] : g[t]) {if (dist[x] > dist[t] + w) {dist[x] = dist[t] + w;cnt[x] = cnt[t] + 1;if (!st[x]) {q.push(x);}if (cnt[x] >= n) {cout << "Yes" << endl;return;}}}}cout << "No" << endl;return;
}int main() {cin >> n >> m;int a, b, c;for (int i = 0; i < m; ++i) {cin >> a >> b >> c;g[a].emplace_back(make_pair(b,c));}spfa();return 0;
}
查看全文
99%的人还看了
相似问题
- 【剑指offer|图解|链表】链表的中间结点 + 链表中倒数第k个结点
- 【数据结构初阶(3)】双向带头结点循环链表
- 单链表相关面试题--4.输入一个链表,输出该链表中倒数第k个结点
- 王道数据结构课后代码题p150 15.设有一棵满二叉树(所有结点值均不同),已知其先序序列为 pre,设计一个算法求其后序序列post。(c语言代码实现)
- 【数据结构】树的基本性质(计算树的总结点数与叶结点数)
- 【数据结构】树与二叉树(五):二叉树的顺序存储(初始化,插入结点,获取父节点、左右子节点等)
- NowCoder | 链表中倒数第k个结点
- 设一棵完全二叉树具有1000个结点,则此完全二叉树有()叶子结点,有()个度为2的结点。
- 11.3递归建二叉树,二叉树函数规范化输入输出,一些二叉树性质,求叶子结点与树的高度
- 二叉树第i层结点个数
猜你感兴趣
版权申明
本文"acwing算法基础之搜索与图论--spfa算法":http://eshow365.cn/6-37915-0.html 内容来自互联网,请自行判断内容的正确性。如有侵权请联系我们,立即删除!
- 上一篇: jenkins分步式构建环境(agent)
- 下一篇: js运算,笔试踩坑知识点