【Floyd】AtCoder ABC375 F. Road Blocked
前言
Floyd 算法(弗洛伊德算法)是解决图论中全源最短路径问题的一种经典算法。全源最短路径问题是指对于给定的一个带权有向图(也可以是无向图,将无向图看作双向有向图即可),求出每一对顶点之间的最短路径长度。Floyd 算法是动态规划思想的一个典型应用,动态规划的过程是引入一个中转节点来松弛路径。
题目
https://atcoder.jp/contests/abc375/tasks/abc375_f
题意
第一行,输入三个正整数
接下来
最后输入
- 1 i:将输入的第
条边删除(永久生效) - 2 x y:询问图中节点
之间的最短距离
对于每个类型 2 的询问,都输出最短距离。若无论如何无法抵达,则输出
保证:无向图中没有重边和自环;类型 1 的询问至多只有 min
题解
对于询问类型 2,本质是询问全源最短路径长度,Floyd 算法时间复杂度为
使用 Floyd 算法维护全源最短路径长度,初始化操作是将全部路径置为无穷大。对于操作类型 1,相当于重新将一条无向边置为无穷大。
但此时引入一个新的问题:若按照询问的顺序进行删边,由于所删边的节点可能是其他最短路径的中转接点,则可能影响到多条路径,故不得不重新跑一边 Floyd 算法。类型 1 的询问次数在 min(
删除一条边,不得不重新将 Floyd 算法重跑一遍,单次操作时间复杂度为
反向执行一次类型 1 的操作,相当于更新一条无向边的长度,本质是更新了两个中转节点,执行 min(
因此,可以反向考虑执行类型 1 的操作。具体的算法步骤如下:
- 将一张无向图的全部边均置为无穷大;
- 将全部从未删除的边初始化到无向图中;
- 执行 Floyd 算法,计算出全源最短路径长度;
- 反向执行询问操作,对于类型 2 的询问,直接输出最短路径长度;对于类型 1 的询问,尝试更新无向边的长度,若当前要更新的长度大于当前无向边长度,则放弃更新,否则更新,并以该无向边的两个节点作为中转节点进行更新全源最短路径长度。
时间复杂度:
空间复杂度:
参考代码
#include<bits/stdc++.h> using namespace std; using ll = long long; constexpr ll INF = 1e18; int n, m, q; ll a[301][301]; bool d[45007]; void floyd_(int k) {//引入节点 k 作为中转节点 for (int i = 1; i <= n; ++ i) { if (i == k) continue; for (int j = 1; j <= n; ++ j) { a[i][j] = min(a[i][j], a[i][k] + a[k][j]); } } } int main() { ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr); cin >> n >> m >> q; vector<int> x(m + 1), y(m + 1), w(m + 1), t(q), u(q), v(q); for (int i = 1; i <= n; ++ i) for (int j = 1; j <= n; ++ j) a[i][j] = INF; for (int i = 1; i <= m; ++ i) cin >> x[i] >> y[i] >> w[i]; for (int i = 0; i < q; ++ i) { cin >> t[i] >> u[i]; if (t[i] == 2) cin >> v[i]; else d[u[i]] = true; } for (int i = 1; i <= m; ++ i) if (!d[i]) a[x[i]][y[i]] = a[y[i]][x[i]] = w[i]; for (int k = 1; k <= n; ++ k) floyd_(k); stack<ll> stk; for (int i = q - 1; i >= 0; -- i) { if (t[i] == 2) stk.emplace(a[u[i]][v[i]] == INF ? -1 : a[u[i]][v[i]]); else { int &id = u[i]; bool flag = false; if (a[x[id]][y[id]] > w[id]) { a[x[id]][y[id]] = w[id]; flag = true; } if (a[y[id]][x[id]] > w[id]) { a[y[id]][x[id]] = w[id]; flag = true; } if (flag) floyd_(x[id]), floyd_(y[id]); } } while (!stk.empty()) { cout << stk.top() << '\n'; stk.pop(); } return 0; }
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 实操Deepseek接入个人知识库
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
· 【.NET】调用本地 Deepseek 模型