1 条题解
-
0
自动搬运
来自洛谷,原作者为

_rqy
**搬运于
2025-08-24 21:46:24,当前版本为作者最后更新于2017-12-23 16:50:31,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
对于这个东西,有一个结论(Karp1977年的论文):
我们新建一个节点,从它到每个点连一条权值任意的边(比如都是0),再令表示从新建的点到点恰好经过条边的最短路,那么有
$$ans=\min_{1\leq i\leq n, F_{n+1}(i)\neq\infty}\max_{j=1}^{n}\left[\frac{F_{n+1}(v)-F_k(v)}{n+1-k}\right] $$具体证明请看我的博客
虽然代码不是跑的最快的但是理论复杂度低(没办法,数据不卡SPFA),是的(而且代码也是最短的,只有0.71KB,不比Dijkstra难写)
#include <algorithm> #include <cstdio> const int N = 3050; const int M = 10050; const double INF = 1e12; double F[N][N], w[M]; int u[M], v[M]; int main() { int n, m, i, j; scanf("%d%d", &n, &m); for (i = 0; i < m; ++i) scanf("%d%d%lf", &u[i], &v[i], &w[i]); for (i = 0; i <= n; ++i) for (j = 1; j <= n; ++j) F[i][j] = i ? INF : 0; for (i = 0; i < n; ++i) for (j = 0; j < m; ++j) F[i + 1][v[j]] = std::min(F[i + 1][v[j]], F[i][u[j]] + w[j]); double ans = 1e7, ans1; for (i = 1; i <= n; ++i) if (F[n][i] < 1e11) { ans1 = -INF; for (j = 0; j < n; ++j) ans1 = std::max(ans1, (F[n][i] - F[j][i]) / (n - j)); ans = std::min(ans, ans1); } printf("%.8lf\n", ans); return 0; }下面还有一个空间复杂度极低(70MB->1.9MB),稍长一点(0.71KB->0.98KB),稍慢一点(3936ms->4468ms)的实现,算了两遍,滚动数组(实际上,上面的代码在BZOJ上MLE,因为BZOJ这题空间64M)
#include <algorithm> #include <cstdio> const int N = 3050; const int M = 10050; const double INF = 1e12; double _F[2][N], Fn[N], w[M], maxv[N]; int u[M], v[M]; int main() { int n, m, i, j; scanf("%d%d", &n, &m); for (i = 0; i < m; ++i) scanf("%d%d%lf", &u[i], &v[i], &w[i]); double *F = _F[0], *G = _F[1]; for (i = 1; i <= n; ++i) G[i] = 0; for (i = 0; i < n; ++i, std::swap(F, G)) { for (j = 1; j <= n; ++j) F[j] = INF; for (j = 0; j < m; ++j) F[v[j]] = std::min(F[v[j]], G[u[j]] + w[j]); } for (i = 1; i <= n; ++i) Fn[i] = G[i]; double ans = 1e7; for (i = 1; i <= n; ++i) maxv[i] = Fn[i] / n, G[i] = 0; for (i = 0; i < n; ++i, std::swap(F, G)) { for (j = 1; j <= n; ++j) F[j] = INF; for (j = 0; j < m; ++j) F[v[j]] = std::min(F[v[j]], G[u[j]] + w[j]); for (j = 1; j <= n; ++j) maxv[j] = std::max(maxv[j], (Fn[j] - F[j]) / (n - i - 1)); } for (i = 1; i <= n; ++i) if (Fn[i] < 1e11) ans = std::min(ans, maxv[i]); printf("%.8lf\n", ans); return 0; }
- 1
信息
- ID
- 2272
- 时间
- 5000ms
- 内存
- 512MiB
- 难度
- 6
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者