分层图最短路,CF 1725M - Moving Both Hands

一、题目

1、题目描述

2、输入输出

2.1输入

2.2输出

3、原题链接

1725M - Moving Both Hands


二、解题报告

1、思路分析

题意看似很简单,就是问我们两个人分别处于1, p两个点上,二者同时出发,相遇时二者所用路径之和的最小值

不难想到求1为源点的最短路,但是我们发现将路径从相遇点分为两段的话,一段是从1出发,一段从另一边出发,原始的堆优化dijkstra似乎不能用了

类似网络流对于图的处理,我们也将每条边建一条反向边

这样以来,图中的边无非两种状态:0(正向),1(反向)

那么我们最小方案中两人的路径可以看作从1出发的人先走若干0边,再走若干1边

也就是说,我们从1出发,如果先前走的都是0边,我们下一条边可以0可以1

但是一旦走了一条1边,就只能走1边了

按照上述原则,我们建图,跑dijkstra即可,详细实现看代码

2、复杂度

时间复杂度: O(N + MlogM)空间复杂度:O(N + M)

3、代码详解

状态不太好,直接无脑define int long long 了 ​
#include <bits/stdc++.h>
using i64 = long long;
using i128 = __int128;
#define int long long
using PII = std::pair<int, int>;
using PIII = std::pair<int, PII>;
const int inf = 1e18 + 7, P = 1e9 + 7;

struct edge {
    int v, w, nxt;
    bool inv;
};

void solve() {
    int n, m;
    std::cin >> n >> m;
    std::vector<int> head(n, -1);
    std::vector<edge> adj;
    adj.reserve(m << 1);

    auto addedge = [&](int u, int v, int w, bool inv) -> void {
        adj.push_back( { v, w, head[u], inv } ), head[u] = adj.size() - 1;
    };

    for (int i = 0, u, v, w; i < m; ++ i) {
        std::cin >> u >> v >> w;
        -- u, -- v;
        addedge(u, v, w, 0);
        addedge(v, u, w, 1);
    }

    std::priority_queue<PIII, std::vector<PIII>, std::greater<PIII>> pq;
    std::vector<std::array<int, 2>> dst(n, { inf, inf } );
    pq.push( { 0, { 0, 1 } } );
    pq.push( { 0, { 0, 0 } } );
    while (pq.size()) {
        auto [d, p] = pq.top();
        auto [u, u_inv] = p;
        pq.pop();
        if (d > dst[u][u_inv]) continue;

        for (int i = head[u]; ~i; i = adj[i].nxt) {
            int v = adj[i].v, w = adj[i].w;
            bool e_inv = adj[i].inv;
            int newd = d + w;
            if ((e_inv == 1 || u_inv == 0) && newd < dst[v][e_inv]) {
                dst[v][e_inv] = newd;
                pq.push( { newd, { v, e_inv } } );
            }
        }
    }

    for (int i = 1; i < n; ++ i) {
        int out = std::min(dst[i][0], dst[i][1]);
        std::cout << (out < inf ? out : -1) << " \n"[i == n - 1];
    }

}
#undef int


int main(int argc, char** argv) {
    std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
    int _ = 1;
    // std::cin >> _;
    while (_ --)
        solve();
    return 0;
}

  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

EQUINOX1

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值