ABC236G
对于一个 p×m 的矩阵 A,与 m×q 的矩阵 B,定义广义矩阵乘法 A×B=C 的结果是一个 p×q 的矩阵 C,满足:
Ci,j=(Ai,1⊗B1,j)⊕(Ai,2⊗B2,j)⊕⋯⊕(Ai,n⊗Bn,j)
其中 ⊗ 和 ⊕ 是两种二元运算。
一些约定:
- ⊗ 有交换律:a⊗b=b⊗a
- ⊗ 有结合律:(a⊗b)⊗c=a⊗(b⊗c)
- ⊗ 对 ⊕ 有分配律:a⊗(b⊕c)=(a⊗b)⊕(a⊗c)
若 ⊗ 有交换律,结合律,⊗ 对 ⊕ 有分配律,那么广义的矩阵乘法就满足结合律。
下面证明 ⊗=max,⊕=min 的广义矩阵乘法具有结合律:
首先显然 max 有交换律和结合律,那么 max(a,min(b,c))=min(max(a,b),max(a,c)) 也是显然的。
回到原问题,令 f(v,i) 表示从 1 出发,经过 i 条边到达点 v 的最早时间,w(u,v) 表示边 u→v 被加入的最小时间,可以得到转移:
f(v,i)=min1≤u≤n{max(f(u,i−1),w(u,v))}
其中 f(1,0)=0,其余均为 ∞。
不难发现这个由上面的结论可以矩阵快速幂优化:
[f(1,i)f(2,i)f(3,i)⋮f(n,i)]=[w(1,1),w(2,1),⋯,w(n,1)w(1,2),w(2,2),⋯,w(n,2)w(1,3),w(2,3),⋯,w(n,3)⋱w(1,n),w(2,n),⋯,w(n,n)][f(1,i−1)f(2,i−1)f(3,i−1)⋮f(n,i−1)]
时间复杂度 O(n3logL)。
Code:
#include <bits/stdc++.h>
using namespace std;
const int N = 105, inf = 0x3f3f3f3f;
int n, m, L;
struct mat {
int a[N][N];
mat operator * (const mat &x) const {
mat res; memset(res.a, 0x3f, sizeof res.a);
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= n; ++j)
for (int k = 1; k <= n; ++k)
res.a[i][j] = min(res.a[i][j], max(a[i][k], x.a[k][j]));
return res;
}
} f;
mat qpow(mat x, int y) {
mat res; memset(res.a, 0x3f, sizeof res.a);
for (int i = 1; i <= n; ++i) res.a[i][i] = 0;
while (y) {
if (y & 1) res = res * x;
x = x * x;
y >>= 1;
}
return res;
}
int main() {
scanf("%d%d%d", &n, &m, &L);
memset(f.a, 0x3f, sizeof f.a);
for (int i = 1, u, v; i <= m; ++i) {
scanf("%d%d", &u, &v);
f.a[u][v] = min(f.a[u][v], i);
}
f = qpow(f, L);
for (int i = 1; i <= n; ++i) printf("%d ", f.a[1][i] != inf ? f.a[1][i] : -1);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话