Atcoder Beginner Contest 236 G Good Vertices
G. Good Vertices
题目大意
给定一张有向图,初始无边,然后每一时刻都会加一条边,可能会有自环,但无重边。问每个点最早在第几时刻,存在一条从号点到该点的长度为的路径。
解题思路
问题首先可以转化成,求号点到号点的所有 长度为路径中添加边时刻的最大值 的最小值。
设表示从 号点出发长度为 到达 号点的答案,则 ,其中 表示边 添加的时刻。
时间复杂度为 ,而 高达 。
关于路径长度的问题一般的优化就是矩阵快速幂来求,但一般都是需要递推式是线性的。
从官方题解的描述来看,这里涉及到两个运算 和 ,在抽象代数中 是构成半环(环的基础上把逆元条件去掉)的,即 是交换幺半群, 是半群,(当然反过来也是),由此俩运算组成的矩阵乘法具有结合律,因而可以用矩阵快速幂优化。
虽说这学期刚学了近世代数,对于半环的矩阵运算具有结合律留待证明
神奇的代码
#include <bits/stdc++.h> using namespace std; typedef long long LL; const int inf = 1e9 + 7; int main(void) { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int n, t, l; cin >> n >> t >> l; vector<vector<int>> ma(n, vector<int>(n, inf)); auto result = ma; for(int i = 1; i <= t; ++ i){ int u, v; cin >> u >> v; -- u; -- v; ma[u][v] = i; } auto multi = [](const vector<vector<int>> &a, const vector<vector<int>> &b){ vector<vector<int>> c(a.size(), vector<int>(b[0].size(), inf)); for(int i = 0; i < a.size(); ++ i) for(int j = 0; j < b[0].size(); ++ j) for(int k = 0; k < a[0].size(); ++ k){ c[i][j] = min(c[i][j], max(a[i][k], b[k][j])); } return c; }; for(int i = 0; i < n; ++ i) result[i][i] = -inf; while(l){ if (l & 1) result = multi(result, ma); ma = multi(ma, ma); l >>= 1; } for(int i = 0; i < n; ++ i){ if (result[0][i] == inf) result[0][i] = -1; cout << result[0][i] << " \n"[i == n - 1]; } return 0; }
本文作者:~Lanly~
本文链接:https://www.cnblogs.com/Lanly/p/15850303.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步