From df296722680b4da549bfccd52658846c665165ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=B5=B7?= <10402852@qq.com> Date: Thu, 4 Jan 2024 14:53:06 +0800 Subject: [PATCH] 'commit' --- TangDou/Topic/POJ3259.cpp | 50 ++++++++++++++++++++++++++++++ TangDou/Topic/【Floyd专题】.md | 31 ++++++++++++++++++ 2 files changed, 81 insertions(+) create mode 100644 TangDou/Topic/POJ3259.cpp diff --git a/TangDou/Topic/POJ3259.cpp b/TangDou/Topic/POJ3259.cpp new file mode 100644 index 0000000..f2cd9a1 --- /dev/null +++ b/TangDou/Topic/POJ3259.cpp @@ -0,0 +1,50 @@ +#include +#include +#include +#include +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; +} \ No newline at end of file diff --git a/TangDou/Topic/【Floyd专题】.md b/TangDou/Topic/【Floyd专题】.md index 317648c..837022c 100644 --- a/TangDou/Topic/【Floyd专题】.md +++ b/TangDou/Topic/【Floyd专题】.md @@ -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 \ No newline at end of file