CF576D Flights for Regular Customers 题解

本文介绍了一种使用 bitset 和广度优先搜索解决 CF576D 问题的方法,该问题要求找出最短飞行路线及所需时间。通过排序航班时间并利用 bitset 更新可达节点,最终实现了高效算法。

CF576D Flights for Regular Customers

CF576D Flights for Regular Customers

没想到用 b i t s e t \tt bitset bitset

首先考虑肯定是对于 d d d 排序一下进行计算。

我们维护一个矩阵表示其中 a u , v a_{u, v} au,v 表示是否存在 u → v u \to v uv 的路径。

我们需要求出对于一个时间 t t t 可以到达哪些点,之后我们就在只有这些边的图上进行广搜即可。

注意我们的邻接矩阵是存图的,之后我们更新能到达哪些点的时候是用传递闭包更新的。不要把两个弄错了。

可以保证每个答案都会被计算到。

#include <bits/stdc++.h>
using namespace std;

//#define Fread
//#define Getmod

#ifdef Fread
char buf[1 << 21], *iS, *iT;
#define gc() (iS == iT ? (iT = (iS = buf) + fread (buf, 1, 1 << 21, stdin), (iS == iT ? EOF : *iS ++)) : *iS ++)
#define getchar gc
#endif // Fread

template <typename T>
void r1(T &x) {
	x = 0;
	char c(getchar());
	int f(1);
	for(; c < '0' || c > '9'; c = getchar()) if(c == '-') f = -1;
	for(; '0' <= c && c <= '9';c = getchar()) x = (x * 10) + (c ^ 48);
	x *= f;
}

template <typename T,typename... Args> inline void r1(T& t, Args&... args) {
    r1(t);  r1(args...);
}

const int maxn = 150 + 5;
const int maxm = maxn << 1;
typedef long long ll;
const ll inf = 1e18;
int n, m;
struct Edge {
    int u, v, d;
    int operator < (const Edge &z) const {
        return d < z.d;
    }
}E[maxn];

ll d[maxn];

struct Matrix {
    bitset<maxn> a[maxn];
    Matrix operator * (const Matrix &z) const {
        Matrix res;
        for(int i = 0; i < n; ++ i) {
            for(int k = 0; k < n; ++ k) if(a[i][k])
                res.a[i] |= z.a[k];
        }
        return res;
    }
}tp, F;

void ksm(Matrix& res, Matrix tmp, int mi) {
    while(mi) {
        if(mi & 1) res = res * tmp;
        mi >>= 1;
        tmp = tmp * tmp;
    }
}

signed main() {
//    freopen("S.in", "r", stdin);
//    freopen("S.out", "w", stdout);
    int i, j;
    r1(n, m);
    for(i = 1; i <= m; ++ i) {
        r1(E[i].u, E[i].v, E[i].d);
        -- E[i].u, -- E[i].v;
    }
    sort(E + 1, E + m + 1);
    F.a[0][0] = 1;
    int t(0);
    ll ans(inf);
    for(i = 1; i <= m; ++ i) {
        int las = t;
        t = E[i].d;
        ksm(F, tp, t - las);
        static queue<int> q; while(!q.empty()) q.pop();
        tp.a[E[i].u][E[i].v] = 1;
        for(j = 0; j < n; ++ j)
            if(F.a[0][j]) d[j] = 0, q.push(j);
            else d[j] = inf;
        while(!q.empty()) {
            int u = q.front(); q.pop();
            for(j = 0; j < n; ++ j) if(tp.a[u][j] && d[j] == inf) {
                d[j] = d[u] + 1;
                q.push(j);
            }
        }
        ans = min(ans, d[n - 1] + t);
    }
    if(ans == inf) return puts("Impossible"), 0;
    else printf("%lld\n", ans);
	return 0;
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值