嘘~ 正在从服务器偷取页面 . . .

洛谷P1613 跑路 题解


洛谷P1613 跑路 题解

题目链接:P1613 跑路

题意

cxy 买了一个空间跑路器,每秒钟可以跑 \(2^k\) 千米(\(k\) 是任意自然数)。

当然,这个机器是用 long long 存的,所以总跑路长度不能超过 \(2^{63}-1\) 千米。

cxy 的家到公司的路可以看做一个有向图,cxy 家为点 \(1\),公司为点 \(n\),每条边长度均为一千米。

cxy 想每天能醒地尽量晚,所以让你帮他算算,他最少需要几秒才能到学校。

数据保证 \(1\)\(n\) 至少有一条路径。

输入格式

第一行两个整数 \(n,m\),表示点的个数和边的个数。

接下来 \(m\) 行每行两个数字 \(u,v\),表示一条 \(u\)\(v\) 的边。

输出格式

一行一个数字,表示到公司的最少秒数。

数据范围

\(n \le 50,~m \le 10000\),最优解路径长度 \(\le 2^{63}-1\)

倍增好题。注意到贪心不一定是最优的,因此考虑dp。

\(g_{i,j,k}\) 表示 \(i,j\) 之间是否存在恰好 \(2^k\) 的路径,则 \[ g_{i,j,k} = \bigvee_{l=1}^{n} \left(g_{i,l,k-1} \land g_{l,j,k-1}\right) \]\(d_{i,j}\)\(i,j\) 间的最短路,则 \(d_{i,j} = 1\) 的充分条件为「原图存在边 \(i \to j\)\(g_{i,j,k} = \mathtt{True}\)

注意到 \(n\) 很小,所以直接 \(\mathtt{Floyd}\) 即可(不会有人到这一步都没发现吧

时间复杂度 \(\mathcal{O}(kn^3)\)\(k = 63\)

代码:

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
#define rep(i,a,b) for(int i=a; i<=b; i++)
void up(int &x,int y) { x < y ? x = y : 0; }
void down(int &x,int y) { x > y ? x = y : 0; }
#define N ((int)(65))

bitset<N> g[N][N];
int n,m,d[N][N];
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    // freopen("check.in","r",stdin);
    // freopen("check.out","w",stdout);
    cin >> n >> m;
    memset(d,0x3f,sizeof(d));
    for(int i=1,u,v; i<=m; i++)
    {
        cin >> u >> v;
        d[u][v] = 1; g[u][v][0] = 1;
    }
    rep(k,1,63) rep(i,1,n) rep(j,1,n) rep(l,1,n)
        if(g[i][l][k-1] & g[l][j][k-1])
        { g[i][j][k] = 1; d[i][j] = 1; }
    rep(k,1,n) rep(i,1,n) rep(j,1,n)
        down(d[i][j], d[i][k] + d[k][j]);
    cout << d[1][n] << '\n';
    return 0;
}

文章作者: q779
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明来源 q779 !
评论
  目录