标签:amp 调用 ble str 时间复杂度 时间 矩阵快速幂 bre 去掉
考虑枚举最优状态是哪些边解锁了,哪些边没有。这样真的有 \(2^n\) 种情况吗?并不是的。将所有边按照解锁需要走过边的数量排序。解锁边的顺序必然是排好序的这样。所以考虑只解锁前 \(i\) 条边,走到 \(n\) 的最短距离是多少。
所以我们可以这样:每次枚举新解锁了哪一条边,如果当前边需要走 \(i\) 步才能解锁,那么看走 \(i\) 条边并解锁这个边后可以到哪些点,用那些点跑一边多源 dfs
寻找到终点的最短路,更新答案即可。
然而这时间复杂度 \(\mathcal O(n^3m\log n)\) 并不能过去。瓶颈是矩阵快速幂。由于矩阵是0/1
矩阵,所以使用bitset
优化即可。比较无脑的bitset
可以维护矩阵的行和列,维护两个bitset
数组,这样比较方便写。当然也可以只维护一个bitset
,这样难理解,而且非常非常没必要。
bitset
优化0/1
矩阵的乘法。#include <cstdio>
#include <bitset>
#include <queue>
#include <algorithm>
using namespace std;
typedef long long ll;
const int NM = 155;
const ll infll = 0x3f3f3f3f3f3f3f3fll;
typedef bitset<150> bt;
int n, m;
struct Edge {
int u, v, w;
inline bool operator < (const Edge &d) const { return w < d.w; }
} eg[NM];
struct Mat {
bt A[150];
inline bt & operator [] (const int i) { return A[i]; }
inline const bt & operator [] (const int i) const { return A[i]; }
//因为 Mat * 不能保存 const Mat * 的东西
//所以必须有一种返回 const Mat * 的调用方法
} A;
bt operator * (const Mat &A, const bt &B) {
static bt ret;
for (int i = 0; i < n; ++i) ret[i] = (A[i] & B).any();
return ret;
}
Mat operator * (const Mat &A, const Mat &B) {
static Mat ret;
for (int i = 0; i < n; ++i) ret[i].reset();
for (int i = 0; i < n; ++i)
for (int j = 0; j < n; ++j)
if (A[i][j]) ret[i] |= B[j];
return ret;
}
void ksm(bt &A, Mat B, int c) {
for (; c; c >>= 1, B = B * B)
if (c & 1) A = B * A;
}
bt go;
queue<int> Q;
ll dis[NM];
int main() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= m; ++i) {
scanf("%d%d%d", &eg[i].u, &eg[i].v, &eg[i].w);
--eg[i].u, --eg[i].v;
}
sort(eg + 1, eg + m + 1);
go[0] = 1;
ll ans = infll;
for (int i = 1, t = 0; i <= m; ++i) {
if (eg[i].w >= ans) break ;
if (eg[i].w != t) ksm(go, A, eg[i].w - t);
t = eg[i].w;
A[eg[i].v][eg[i].u] = 1;
for (int j = 0; j < n; ++j)
if (go[j]) Q.push(j), dis[j] = 0;
else dis[j] = infll;
while (Q.size()) {
int u = Q.front();
Q.pop();
for (int j = 0; j < n; ++j)
if (A[j][u] && dis[j] == infll) {
dis[j] = dis[u] + 1;
Q.push(j);
}
}
ans = min(ans, t + dis[n - 1]);
}
if (ans == infll) printf("Impossible\n");
else printf("%lld\n", ans);
return 0;
}
【CodeForces576D】Flights for Regular Customers
标签:amp 调用 ble str 时间复杂度 时间 矩阵快速幂 bre 去掉
原文地址:https://www.cnblogs.com/YouthRhythms/p/13307435.html