• Codeforces Round #816 (Div. 2)


    Codeforces Round #816 (Div. 2)

    传送门: Codeforces Round #816 (Div. 2)

    参考视频:https://www.bilibili.com/video/BV1ZG41147HH

    E. Long Way Home

    prob:

    n个点m条无向边,同时定义两点间无向特殊边的代价为这两点标号的平方,即 ( i − j ) 2 (i - j)^2 (ij)2,问从1号点出发到每个点且经过特殊边不超过k次的最短路

    n,m 1e5, k 20 ,边权w 1e9 均为正数

    ideas:

    如果不考虑特殊边,直接dijkstra

    如果最多经过一条特殊边,

    考虑最后一条边一定是特殊边的最短路,在刚开始dijkstra的dist数组基础上dp, d p [ i ] = m i n { d i s t [ j ] + ( i − j ) 2 } dp[i]= min\{dist[j] + (i - j)^2\} dp[i]=min{dist[j]+(ij)2}

    转移次数太多了,考虑优化,可以发现当j < i 的时候 j 的取值具有决策单调性(可打表得出,

    于是这部分可以分治完成, s o l v e ( l , r , x , y ) solve(l, r, x, y) solve(l,r,x,y)表示当前正在处理 [ l , r ] [l, r] [l,r],决策可能的区间为 [ x , y ] [x, y] [x,y]

    已知最多经过k条特殊边且最后一次是特殊边的情况,扩展到一般情况(即不一定最后一次是特殊边)

    在经过k条的基础上进行dijkstra

    已知最多经过k条特殊边的情况,求最多经过k+1条特殊边,由刚开始最多经过一条特殊边的情况扩展即可

    code:

    刚开始dijkstra里面dist和i写反了,de了一个世纪,我不明白这样错为什么还能过81个点

    注意dijkstra里面每个都要放进去,不过如果没有每个放的话样例也体现了,样例挺友好的w

    #include "bits/stdc++.h"
    
    using namespace std;
    
    typedef long long ll;
    typedef pair<int, ll> pii;
    const ll inf = 0x3f3f3f3f3f3f3f3f;
    const ll N = 1e5 + 10;
    
    struct node {
        int to;
        ll len;
    };
    
    vector<node> g[N];
    int n, m, k;
    ll dist[N]; // the min dist
    ll f[N]; // the min dist with last time is a flight
    
    void dij() {
        priority_queue<pii, vector<pii>, greater<> > que;
    
        for (int i = 1; i <= n; ++i) {
            que.push({dist[i], i});
        }
    
        while (!que.empty()) {
            auto[dis, u] = que.top();
            que.pop();
    
            if (dis > dist[u]) continue;
    
            for (auto[to, len] : g[u]) {
                if (dist[u] + len < dist[to]) {
                    dist[to] = dist[u] + len;
                    que.push({dist[to], to});
                }
            }
        }
    }
    
    ll cal(int x, int p) {
        return dist[p] + (ll) ((ll) (p - x) * (ll) (p - x));
    }
    
    void solve(int l, int r, int x, int y) { // cal f , divide and conquer
        if (l > r) return;
        int mid = (l + r) >> 1;
        int p = x;
        ll mn = inf;
        for (int i = x; i <= y && i <= mid - 1; ++i) {
            ll tmp = cal(mid, i);
            if (tmp < mn) {
                mn = tmp;
                p = i;
            }
        }
        f[mid] = min(f[mid], cal(mid, p));
    //    cerr << mid << " " << p << endl;
        solve(l, mid - 1, x, p), solve(mid + 1, r, p, y);
    }
    
    signed main() {
        
        scanf("%d%d%d", &n, &m, &k);
    
        for (int i = 1, u, v, len; i <= m; ++i) {
            scanf("%d%d%d", &u, &v, &len);
            g[u].push_back({v, len});
            g[v].push_back({u, len});
        }
    
        memset(dist, 0x3f, sizeof dist);
        dist[1] = 0;
        dij();
    
        for (int kkk = 0; kkk < k; ++kkk) {
            memset(f, 0x3f, sizeof f);
    
            solve(1, n, 1, n);
    
            reverse(dist + 1, dist + n + 1);
            reverse(f + 1, f + n + 1);
    
            solve(1, n, 1, n);
    
            reverse(dist + 1, dist + n + 1);
            reverse(f + 1, f + n + 1);
    
            for (int i = 1; i <= n; ++i) {
                dist[i] = min(dist[i], f[i]);
            }
    
            dij();
        }
    
        for (int i = 1; i <= n; ++i) {
            printf("%lld ", dist[i]);
        }
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
  • 相关阅读:
    【JavaSE语法】类和对象(二)
    LeetCode 第8题:字符串转换整数(Python3解法)
    java-php-python-红河旅游信息服务系统计算机毕业设计
    Linux检查Docker镜像,容器的磁盘空间
    OR青年学员访谈特辑 | 充分发挥主观能动性 自主探索 提升能力
    Java LinkedList链表、HashSet、HashMap
    java设计模式学习笔记总结
    使用wireshark抓包,验证客户端和服务端SSL通信时指定的算法套件
    使用cpolar配合Plex打造个人媒体站,畅享私人影音娱乐空间
    ios上架上传构建版本的windows工具
  • 原文地址:https://blog.csdn.net/qq_39602052/article/details/126561378