AcWing 852. spfa判断负环的算法如何改写为长尾词?

2026-04-12 05:091阅读0评论SEO教程
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计733个文字,预计阅读时间需要3分钟。

AcWing 852. spfa判断负环的算法如何改写为长尾词?

题目:给定一个包含点及边方向的图,判断图中是否存在负权回路。

给定一个整数 $n$ 个点和一个边集合,边集合中的每条边是一个包含起点、终点和权重的三元组。判断图中是否存在负权回路。

输入格式:第一行包含一个整数 $n$,表示点的数量。接下来 $m$ 行,每行包含三个整数 $a, b, c$,表示一条从点 $a$ 到点 $b$ 的边,权重为 $c$。

输出格式:输出一个字符串 YES 或 NO,表示图中是否存在负权回路。

注意:$1 \leq n \leq 100$,$1 \leq m \leq 100$,$a, b \in [1, n]$,$c \in \mathbb{Z}$。

题目

给定一个 $n$ 个点 $m$ 条边的有向图,图中可能存在重边和自环, 边权可能为负数。

请你判断图中是否存在负权回路。

输入格式 第一行包含整数 $n$ 和 $m$。

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

输出格式 如果图中存在负权回路,则输出 Yes,否则输出 No

数据范围 $1≤n≤2000,1≤m≤10000$,图中涉及边长绝对值均不超过 $10000$。

输入样例:

AcWing 852. spfa判断负环的算法如何改写为长尾词?

3 3 1 2 -1 2 3 4 3 1 -4

输出样例:

Yes

思路

基本思路,判断负环的话就增加一个数组 $cnt$ 记录某点最短距离需要的边数,每次更新时判断下 cnt ?>= n

queue <-- 1 存储变小的点,初始为1 while queue t = q.front q.pop 更新t的所有出边,并将出边端点加入队列

代码

#include <iostream> #include <cstring> #include <queue> using namespace std; const int N = 2010, M = 10010; int n, m; int h[N], e[M], w[M], ne[M], idx; int d[N], cnt[N]; bool st[N]; void add(int a, int b, int c) { e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++ ; } bool spfa() { memset(d, 0x3f, sizeof d); d[1] = 0; queue<int> q; for (int i = 1; i <= n; i ++ ) { q.push(i); st[i] = 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 (d[j] > d[t] + w[i]) { d[j] = d[t] + w[i]; cnt[j] = cnt[t] + 1; if (cnt[j] >= n) return true; // 判断点j的边数 if (!st[j]) { q.push(j); st[j] = true; } } } } return false; } int main() { scanf("%d%d", &n, &m); memset(h, -1, sizeof h); while (m -- ) { int a, b, c; scanf("%d%d%d", &a, &b, &c); add(a, b, c); } if (spfa()) puts("Yes"); else puts("No"); return 0; }

本文共计733个文字,预计阅读时间需要3分钟。

AcWing 852. spfa判断负环的算法如何改写为长尾词?

题目:给定一个包含点及边方向的图,判断图中是否存在负权回路。

给定一个整数 $n$ 个点和一个边集合,边集合中的每条边是一个包含起点、终点和权重的三元组。判断图中是否存在负权回路。

输入格式:第一行包含一个整数 $n$,表示点的数量。接下来 $m$ 行,每行包含三个整数 $a, b, c$,表示一条从点 $a$ 到点 $b$ 的边,权重为 $c$。

输出格式:输出一个字符串 YES 或 NO,表示图中是否存在负权回路。

注意:$1 \leq n \leq 100$,$1 \leq m \leq 100$,$a, b \in [1, n]$,$c \in \mathbb{Z}$。

题目

给定一个 $n$ 个点 $m$ 条边的有向图,图中可能存在重边和自环, 边权可能为负数。

请你判断图中是否存在负权回路。

输入格式 第一行包含整数 $n$ 和 $m$。

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

输出格式 如果图中存在负权回路,则输出 Yes,否则输出 No

数据范围 $1≤n≤2000,1≤m≤10000$,图中涉及边长绝对值均不超过 $10000$。

输入样例:

AcWing 852. spfa判断负环的算法如何改写为长尾词?

3 3 1 2 -1 2 3 4 3 1 -4

输出样例:

Yes

思路

基本思路,判断负环的话就增加一个数组 $cnt$ 记录某点最短距离需要的边数,每次更新时判断下 cnt ?>= n

queue <-- 1 存储变小的点,初始为1 while queue t = q.front q.pop 更新t的所有出边,并将出边端点加入队列

代码

#include <iostream> #include <cstring> #include <queue> using namespace std; const int N = 2010, M = 10010; int n, m; int h[N], e[M], w[M], ne[M], idx; int d[N], cnt[N]; bool st[N]; void add(int a, int b, int c) { e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++ ; } bool spfa() { memset(d, 0x3f, sizeof d); d[1] = 0; queue<int> q; for (int i = 1; i <= n; i ++ ) { q.push(i); st[i] = 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 (d[j] > d[t] + w[i]) { d[j] = d[t] + w[i]; cnt[j] = cnt[t] + 1; if (cnt[j] >= n) return true; // 判断点j的边数 if (!st[j]) { q.push(j); st[j] = true; } } } } return false; } int main() { scanf("%d%d", &n, &m); memset(h, -1, sizeof h); while (m -- ) { int a, b, c; scanf("%d%d%d", &a, &b, &c); add(a, b, c); } if (spfa()) puts("Yes"); else puts("No"); return 0; }