1 条题解

  • 0
    @ 2025-8-24 22:28:17

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar CommonDigger
    AFO

    搬运于2025-08-24 22:28:17,当前版本为作者最后更新于2024-10-04 21:26:30,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    个人建议评绿或蓝。

    类似分层图的思想。

    题意

    说得很清楚,一张有向图,边权由其长度 LL 速度 VV 决定,如果未提供速度,那么就沿用走到这里的上一条边的速度,即 VoldV_{old}。求单源最短路。

    很容易发现,仅使用一维数组 dis[N]dis[N] 是无法体现对速度的处理的。解释:假设你可以花 5 秒走到一个节点,速度为 1,而此时到下一个节点的边没有提供速度,所以你需要沿用 V=1V=1,到达下一个点的时间较慢;同时你可以花 10 秒走到这里,这条路线速度为 8,只用花较短的时间就到达下一个节点。

    所以,定义 dis[N][V]dis[N][V] 表示以速度 vv 到达 nn 号节点的最短时间。

    在最短路算法中,对于每一条边:当它速度不明时,沿用速度 VoldV_{old} 计算边权,尝试更新 dis[to][v_old];否则尝试更新 dis[to][v]。另外,不建议使用 SPFA。

    if(e[i].v==0){ // 这条边速度不明
    // 沿用v__old,更新dis[to][v_old]
    }else{
    // 更新 dis[to][v]
    }
    

    由于最终要求输出路径,所以我们在更新最短路的同时记录这个点是由哪个点走过来的,因为要考虑速度,所以为它多开一维。

    pair<int, int> pre[155][505] // 两个维度分别是 *点编号* 和 *速度*
    pre[to][e[i].v]=make_pair(temp.id, temp.speed); // 由旧点更新到新点
    

    怎么找路径呢? 我做的时候在这里卡了

    首先,确定到达终点最优的状态,循环找出时间最短的速度,即找到使 dis[D][i] 最小的 i。然后再根据 pre 中的记录往后退,直到退回 0 号节点,途中再用数组记录路径(会光标倒退的可以直接输出)。

      int path[505], dx=0, w=0;
        for(int i=1;i<=500;i++){
            if(dis[t][i]<dis[t][w]) w=i;
        } // 找时间最小的状态,记录为 [t][w]
        for(int walker=t, sp=w;walker!=0;){ // 于是从 pre[t][w]开始退
            path[++dx]=walker;
            pair<int, int>g=pre[walker][sp];
            walker=g.first, sp=g.second;
        }
        cout << "0 ";
        for(;dx>0;dx--){ // 倒序输出
            cout << path[dx] << " ";
        }
    

    完整版

    #include "iostream"
    #include "cstring"
    #include "queue"
    using namespace std;
    int head[155], idx, n, m, t;
    pair<int, int> pre[155][505];
    int temp1, temp2, temp3, temp4;
    double dis[155][505];
    struct edge{
        int to, nxt, l, v;
    }e[31250];
    struct point{
        double d;
        int id, speed;
        point(double d, int id, int speed){
            this->d=d;
            this->id=id;
            this->speed=speed;
        }
        friend bool operator <(point p1, point p2){
            return p1.d > p2.d;
        }
    };
    void add_edge(int u, int v, int _v, int l){
        e[++idx].to=v;
        e[idx].l=l;
        e[idx].v=_v;
        e[idx].nxt=head[u];
        head[u]=idx;
    }
    void dijkstra(){ // 差不多是模板了
        memset(dis, 127, sizeof(dis));
        priority_queue<point>q;
        q.push(point(0, 0, 70)); // 点结构体:距离、编号、速度
        while(!q.empty()){
            point temp=q.top();
            q.pop();
            if(temp.d > dis[temp.id][temp.speed]) continue;
            dis[temp.id][temp.speed]=temp.d;
            for(int i=head[temp.id];i;i=e[i].nxt){
                int to=e[i].to;
                if(e[i].v==0){ // 速度不明,沿用旧速度
                    double nd=temp.d+e[i].l*1.0/temp.speed;
                    if(dis[to][temp.speed]>nd){
                        dis[to][temp.speed]=nd;
                        pre[to][temp.speed]=make_pair(temp.id, temp.speed);
                        q.push(point(nd, to, temp.speed));
                    }
                }else{ // 自带速度,正常尝试更新
                    double nd=temp.d+e[i].l*1.0/e[i].v;
                    if(dis[to][e[i].v]>nd){
                        dis[to][e[i].v]=nd;
                        pre[to][e[i].v]=make_pair(temp.id, temp.speed);
                        q.push(point(nd, to, e[i].v));
                    }
                }
            }
        }
    }
    int main(){
        ios::sync_with_stdio(0);
        cin.tie(0);
        cout.tie(0);
        cin >> n >> m >> t;
        for(int i=1;i<=m;i++){
            cin >> temp1 >> temp2 >> temp3 >> temp4;
            add_edge(temp1, temp2, temp3, temp4);
        }
        dijkstra();
        int path[505], dx=0, w=0;
        for(int i=1;i<=500;i++){
            if(dis[t][i]<dis[t][w]) w=i;
        }
        for(int walker=t, sp=w;walker!=0;){
            path[++dx]=walker;
            pair<int, int>g=pre[walker][sp];
            walker=g.first, sp=g.second;
        }
        cout << "0 ";
        for(;dx>0;dx--){
            cout << path[dx] << " ";
        }
    }
    

    21 年发的题目了,24 年 10 月开始写这个题解的时候,提交仅 36,通过5。这道题是真的没人看啊

    • 1

    信息

    ID
    5876
    时间
    1000ms
    内存
    128MiB
    难度
    (无)
    标签
    递交数
    0
    已通过
    0
    上传者