P1266 速度限制(最短路 迪杰斯特拉算法)

题目描述

在这个繁忙的社会中,我们往往不再去选择最短的道路,而是选择最快的路线。开车时每条道路的限速成为最关键的问题。不幸的是,有一些限速的标志丢失了,因此你无法得知应该开多快。一种可以辩解的解决方案是,按照原来的速度行驶。你的任务是计算两地间的最快路线。

你将获得一份现代化城市的道路交通信息。为了使问题简化,地图只包括路口和道路。每条道路是有向的,只连接了两条道路,并且最多只有一块限速标志,位于路的起点。两地 A 和 B,最多只有一条道路从 A 连接到 B。你可以假设加速能够在瞬间完成并且不会有交通堵塞等情况影响你。当然,你的车速不能超过当前的速度限制。

输入格式

第一行是 3 个整数 N,M 和 D (2≤N≤150),表示道路的数目,用  N−1 标记。M 是道路的总数,D 表示你的目的地。

接下来的 M 行,每行描述一条道路,每行有 4 个整数 A (0≤A<N),B (0≤B<N),V (0≤V≤500) 和 L (1≤L≤500),这条路是从 A 到 B 的,速度限制是 V,长度为 L。如果 V 是 0,表示这条路的限速未知。

如果 V 不为 0,则经过该路的时间 T=VL​。否则 T=VoldL​,VoldVold 是你到达该路口前的速度。开始时你位于 0 点,并且速度为 70。

输出格式

输出文件仅一行整数,表示从 00 到 D 经过的城市。

输出的顺序必须按照你经过这些城市的顺序,以 00 开始,以 D 结束。仅有一条最快路线。

输入输出样例

输入 #1复制

6 15 1
0 1 25 68
0 2 30 50
0 5 0 101
1 2 70 77
1 3 35 42
2 0 0 22
2 1 40 86
2 3 0 23
2 4 45 40
3 1 64 14
3 5 0 23
4 1 95 8
5 1 0 84
5 2 90 64
5 3 36 40

输出 #1复制

0 5 2 3 1

解析:

这时一道这么在最小时间内到达D点的题。

我们可以想到最短路算法,迪杰斯特拉算法。每次枚举其速度,这个通道的时间即可。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define N 200005
int n, m, d;
int first[N], Next[N], to[N], sp[N], len[N], tot;
double dis[205][1005];
int vis[205][1005];
pair<int, int> from[205][1005];
void add(int x, int y, int z, int zz)
{
    Next[++tot] = first[x];
    first[x] = tot;
    to[tot] = y;
    sp[tot] = z;
    len[tot] = zz;
    return;
}
void dijkstrar(int x)
{
    priority_queue<pair<double, pair<int, int> > > q;
    for(int i = 1; i <= n; i++)
    {
        for(int j = 1; j <= 505; j++)
        {
            dis[i][j] = 1e9;
            vis[i][j] = 0;
        }
    }
    dis[x][70] = 0;
    q.push(make_pair(0, make_pair(x, 70)));
    while(!q.empty())
    {
        pair<int, int> u = q.top().second;
        q.pop();
        if(vis[u.first][u.second])
        {
            continue;
        }
        vis[u.first][u.second] = 1;
        for(int i = first[u.first]; i; i = Next[i])
        {
            int v = to[i], sped = (sp[i] ? sp[i] : u.second);
            double time = (double)len[i] / (double)sped;
            if(dis[u.first][u.second] + time < dis[v][sped])
            {
                dis[v][sped] = dis[u.first][u.second] + time;
                from[v][sped] = u;
                q.push(make_pair(-dis[v][sped], make_pair(v, sped)));
            }
        }
    }
    return;
}



void write(int x, int v)
{
    if(x == 1)
    {
        printf("0 ");
        return;
    }
    write(from[x][v].first, from[x][v].second);
    printf("%d ", x - 1);
    return;
}
int main()
{
    cin >> n >> m >> d;
    int x,y,zz,z;
    for(int i = 1;i <= m;i++)
    {//从 1开始到 n
        cin >> x>> y >> z>> zz; // x -> y  速度为z 限速为zz 
        x++;
        y++;
        add(x,y,z,zz);
    }
    
    dijkstrar(1);
    d++;

    int maxx = 0;
    dis[d][maxx] = 1e9;
    for(int i = 1;i <= 500;i++)//遍历一边速度
    {
        if(dis[d][i] < dis[d][maxx]) // dis为时间
        {
            maxx = i;
        }
    }
    write(d,maxx);
    return 0;
}

时间复杂度:O(n*m);

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值