CodeForces576DFlights for Regular Customers
Posted youthrhythms
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CodeForces576DFlights for Regular Customers相关的知识,希望对你有一定的参考价值。
题目链接
题目解法
考虑枚举最优状态是哪些边解锁了,哪些边没有。这样真的有 (2^n) 种情况吗?并不是的。将所有边按照解锁需要走过边的数量排序。解锁边的顺序必然是排好序的这样。所以考虑只解锁前 (i) 条边,走到 (n) 的最短距离是多少。
所以我们可以这样:每次枚举新解锁了哪一条边,如果当前边需要走 (i) 步才能解锁,那么看走 (i) 条边并解锁这个边后可以到哪些点,用那些点跑一边多源 dfs
寻找到终点的最短路,更新答案即可。
然而这时间复杂度 (mathcal O(n^3mlog 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
");
else printf("%lld
", ans);
return 0;
}
以上是关于CodeForces576DFlights for Regular Customers的主要内容,如果未能解决你的问题,请参考以下文章
Codeforces 576D Flights for Regular Customers 矩阵快速幂+DP
Codeforces 576D. Flights for Regular Customers(倍增+floyd+bitset优化)
Codeforces Round #576 (Div. 2) B - Water Lily
Codeforces Round #576 (Div. 2) D - Welfare State
Codeforces Round #576 (Div. 2) D. Welfare State
codeforces 576c// Points on Plane// Codeforces Round #319(Div. 1)