2022-01-27 16:31阅读: 139评论: 0推荐: 0

Atcoder Beginner Contest 236 G Good Vertices

G. Good Vertices

题目大意

给定一张有向图,初始无边,然后每一时刻都会加一条边,可能会有自环,但无重边。问每个点最早在第几时刻,存在一条从1号点到该点的长度为l的路径。

解题思路

问题首先可以转化成,求1号点到i号点的所有 长度为l路径中添加边时刻的最大值 的最小值。

dp[i][j]表示从 1号点出发长度为 l到达 i号点的答案,则 dp[i][j]=mink(max(dp[k][j1],w(k,i))),其中 w(k,i)表示边 (k,i)添加的时刻。

时间复杂度为 O(n2L),而 L高达 109

关于路径长度的问题一般的优化就是矩阵快速幂来求,但一般都是需要递推式是线性的。

官方题解的描述来看,这里涉及到两个运算 minmax,在抽象代数中 (Z,min,max)是构成半环(环的基础上把逆元条件去掉)的,即 (Z,min)是交换幺半群, (Z,max)是半群,(当然反过来也是),由此俩运算组成的矩阵乘法具有结合律,因而可以用矩阵快速幂优化。

虽说这学期刚学了近世代数,对于半环的矩阵运算具有结合律留待证明

神奇的代码
#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 中国大陆许可协议进行许可。

posted @   ~Lanly~  阅读(139)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起
  1. 1 404 not found REOL
404 not found - REOL
00:00 / 00:00
An audio error has occurred.