main
黄海 2 years ago
parent 2db9dd62d4
commit df29672268

@ -0,0 +1,50 @@
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
const int INF = 0x3f3f3f3f;
const int N = 502;
int n, m, w;
int g[N][N];
bool floyd() {
for (int k = 1; k <= n; k++)
for (int i = 1; i <= n; i++)
if (g[i][k] != INF) {
for (int j = 1; j <= n; j++)
if (g[i][j] > g[i][k] + g[k][j])
g[i][j] = g[i][k] + g[k][j];
if (g[i][i] < 0) return true;
}
return false;
}
int main() {
int T;
cin >> T;
while (T--) {
cin >> n >> m >> w;
memset(g, INF, sizeof g); // 初始化邻接矩阵
// 双向正值边
while (m--) {
int a, b, c;
cin >> a >> b >> c;
// 注意坑:重边
g[a][b] = g[b][a] = min(c, g[a][b]);
}
// 单向负值边
while (w--) {
int a, b, c;
cin >> a >> b >> c;
g[a][b] = -c;
}
if (floyd())
puts("YES");
else
puts("NO");
}
return 0;
}

@ -5,3 +5,34 @@ $Floyd$算法是一次性求所有结点之间的最短距离,能处理负权
$Floyd$运用了 **动态规划** 的思想,求 $i 、 j$两点的最短距离,可分两种情况考虑,即经过图中某个点 $k$的路径和不经过点 $k$ 的路径,**取两者中的最短路径**。
- 判断负圈
眼尖的人儿可能发现邻接矩阵 $mp$ 中, $mp[i][i]$并没有赋初值$0$,而是 $inf$。并且计算后 $mp[i][i]$的值也不是 $0$,而是 $mp[i][i]=mp[i][u]+……+mp[v][i]$,即从外面绕一圈回来的最短路径,而这正 **用于判断负圈**,即 $mp[i][i]<0$。
相关变形结合题目讲,如:负圈、打印路径、最小环、传递闭包
记录坑点:**重复边**,保留最小的那个。
### 二、模板
```cpp {.line-numbers}
void floyd() {
for (int k = 1; k <= n; k++)
for (int i = 1; i <= n; i++)
if (g[i][k] != inf) //优化
for (int j = 1; j <= n; j++)
if (g[i][j] > g[i][k] + g[k][j])
g[i][j] = g[i][k] + g[k][j];
}
```
### 三、例题
#### [$POJ-3259$ $Wormholes$ 负圈](https://link.juejin.cn/?target=https%3A%2F%2Fvjudge.net%2Fproblem%2FPOJ-3259)
**分析**
给定若干双向正值边和单向负值边,问是否存在负圈(使其时光倒流回到原点)。
所以在第二重循环,求完第$i$个结点后判断。
https://juejin.cn/post/6935691567696969764
Loading…
Cancel
Save