CF576D Flights for Regular Customers
https://www.luogu.com.cn/problem/CF576D
不小心点了一下推荐题目,然后这题就会了
首先每条边按照 d i d_i di从小到大排序,然后维护邻接矩阵,xjb矩阵快速米即可
可以用bitset优化
草,好像没太想清楚
首先如果是直接min转移是没有前途的,没办法优化
考虑矩阵记为是否能够到达,然后加入一条边后可以很容易得到一个点是否能够达到
然后在跑个bfs加上当前边的边权即可
时间复杂度 O ( n 3 m l o g n / w ) O(n^3mlogn/w) O(n3mlogn/w)
#include<bits/stdc++.h>
#define N 205
using namespace std;
struct E {
int u, v, c;
} e[N << 1];
int cmp(E x, E y) {
return x.c < y.c;
}
int n, m, d[N];
struct MT {
bitset<N> a[N];
void init() {
for(int i = 1; i <= n; i ++)
for(int j = 1; j <= n; j ++)
a[i][j] = (i == j);
}
} a, g;
MT mul(MT a, MT b) {
MT c;
for(int i = 1; i <= n; i ++)
for(int k = 1; k <= n; k ++)
if(a.a[i][k])
c.a[i] |= b.a[k];
return c;
}
MT qpow(MT x, int y) {
MT ret; ret.init();
for(; y; y >>= 1, x = mul(x, x)) if(y & 1) ret = mul(ret, x);
return ret;
}
void print(MT a) {
for(int i = 1; i <= n; i ++) {
for(int j = 1; j <= n; j ++) printf("%d ", (int)a.a[i][j]); printf("\n");
} printf("\n");
}
queue<int> q;
int main() {
scanf("%d%d", &n, &m);
for(int i = 1; i <= m; i ++) scanf("%d%d%d", &e[i].u, &e[i].v, &e[i].c);
sort(e + 1, e + 1 + m, cmp);
int lst = 0;
int ans = 2e9;
a.init();
for(int i = 1; i <= m; i ++) {
if(ans < e[i].c) break;
int t = e[i].c - lst; lst = e[i].c;
// print(a), print(qpow(g, t));
a = mul(a, qpow(g, t));
g.a[e[i].u][e[i].v] = 1;
// print(a), print(g);
for(int j = 1; j <= n; j ++) if(a.a[1][j]) d[j] = 0, q.push(j); else d[j] = -1;
while(q.size()) {
int u = q.front(); q.pop();
for(int v = 1; v <= n; v ++) if(g.a[u][v] && d[v] == -1) {
d[v] = d[u] + 1;
q.push(v);
}
}
if(d[n] != -1) ans = min(ans, d[n] + lst);
}
if(ans == (int)2e9) printf("Impossible");
else printf("%d", ans);
return 0;
}