• [CF1442C] Graph Transpositions


    [CF1442C] Graph Transpositions - 分层图最短路

    Description

    给你一个(n)个顶点和(m)条边的有向图。顶点编号从(1)(n)。顶点(1)处有一个标记。

    你可以进行以下两种操作:

    • 移动标记:如果存在一条(u o v)的边,将标记从(u)移动到(v),这个操作需要(1)秒。
    • 图翻转:翻转图上的所有边的方向,将图上每一条边(u o v)替换为(v o u),第(k)次使用这个操作需要耗时(2^{k-1})秒。

    你需要找到将标记从(1)移动到(n)的最短时间,请将答案对(998,244,353)取模。

    Solution

    朴素分层图有 (O(n^2)) 个点,需另辟蹊径

    (C=lceil log_2 n ceil),则当 (k ge C) 时,层数最小不会使得答案更劣

    (kle C) 的部分建分层图跑最短路

    层内连边 (p o q (cost=1)),第 (k) 层到第 (k+1)(i_k o i_{k+1} (cost = 2^k))

    如果无解,说明 (k>C),此时我们优先最小化层数

    每次做完层内转移,然后集体转移到下一层

    (k mod 2=0) 则用正图,否则用反图

    先在层内转移,内连边 (p o q (cost=1))

    后再层间转移,只要 (n) 点还未到达,所有点就一起转移,从 (k) 层到 (k+1) 层,整体加上代价 (2^k)

    这个代价额外存一个偏移量中即可,(f[]) 中记录的代价只是 (k le C) 部分的代价和 (k >C) 部分的层内转移代价,这样 (f[]) 中的数字不用取模,可以比较大小

    由于边权只有 (0/1),总体的时间复杂度还是 (O(m log n))

    最短路过程中记录代价用二维数组 (dis[][]),后续过程用 (f[])

    #include <bits/stdc++.h>
    using namespace std;
    
    #define int long long
    
    const int mod = 998244353;
    const int N = 400005;
    const int M = 25;
    
    int qpow(int p, int q)
    {
        return (q & 1 ? p : 1) * (q ? qpow(p * p % mod, q / 2) : 1) % mod;
    }
    
    int n, m;
    int dis[M][N], f[N];
    bool vis[M][N];
    vector<int> g[2][N];
    
    void spfa()
    {
        queue<pair<int, int>> que;
        dis[0][1] = 0;
        que.push({0, 1});
        vis[0][1] = 1;
        while (que.size())
        {
            auto [k, p] = que.front();
            que.pop();
            for (int q : g[k & 1][p])
            {
                if (dis[k][q] > dis[k][p] + 1)
                {
                    dis[k][q] = dis[k][p] + 1;
                    if (vis[k][q] == 0)
                        que.push({k, q}), vis[k][q] = 1;
                }
            }
            if (k < 18)
                if (dis[k + 1][p] > dis[k][p] + (1ll << k))
                {
                    dis[k + 1][p] = dis[k][p] + (1ll << k);
                    if (vis[k + 1][p] == 0)
                        que.push({k + 1, p}), vis[k + 1][p] = 1;
                }
        }
    }
    
    signed main()
    {
        ios::sync_with_stdio(false);
        cin >> n >> m;
        for (int i = 1; i <= m; i++)
        {
            int t1, t2;
            cin >> t1 >> t2;
            g[0][t1].push_back(t2);
            g[1][t2].push_back(t1);
        }
        memset(dis, 0x3f, sizeof dis);
        memset(f, 0x3f, sizeof f);
        spfa();
        int ans = 1e18;
        for (int i = 0; i < 18; i++)
            ans = min(ans, dis[i][n]);
        if (ans < 1e9)
        {
            cout << ans << endl;
        }
        else
        {
            f[1] = 0;
            queue<int> que, que_next;
            que.push(1);
            que_next.push(1);
            int delta = 0;
            for (int k = 0;; k++)
            {
                while (que.size())
                {
                    int p = que.front();
                    que.pop();
                    for (int q : g[k & 1][p])
                    {
                        if (f[q] > f[p] + 1)
                        {
                            f[q] = f[p] + 1;
                            que.push(q);
                            que_next.push(q);
                        }
                    }
                }
                while (que_next.size())
                {
                    que.push(que_next.front());
                    que_next.pop();
                }
                if (f[n] < 1e9)
                {
                    cout << (f[n] + delta) % mod << endl;
                    return 0;
                }
                delta += qpow(2, k);
                delta %= mod;
            }
        }
    }
    
  • 相关阅读:
    初中几何
    角平分线导致的三角形内外角关系
    解方程
    初中|数学题目整理
    求一次函数解析式
    整式的四则运算
    分式方程
    做辅助线的方法
    线段相等的证明思路
    python2.7安装sqlite3模块
  • 原文地址:https://www.cnblogs.com/mollnn/p/14560282.html
Copyright © 2020-2023  润新知