道路管制PTA(25)(非常简单看懂就会ORZ

乌拉乌拉国有n个城市和m条道路,城市编号为1∼n。由于乌拉乌拉国每一个城市都在创城(创建文明城市),因此,城市之间的道路通行施行道路交通管制:
 已知从城市ui​到城市vi​的道路,需要时间ti​。但是一旦当道路管理员进入某条道路后,任何人在道路管理员未驶出该道路前不允许进入该道路。例如:道路管理员在第4时刻进入该道路,在路上需要花费3时,那么在第4∼6时刻不允许其他人进入改街道,只能第7时刻及其以后进入或者在第4时刻之前进入。
 现在,计算鸭知道,道路管理员从0时刻出发,依次经过g个城市,计算鸭从时刻k出发,从城市a前往城市b。请问,计算鸭最少需要多长时间。

输入格式:

输入的第一行给出两个整数n,m——表示城市的数量和道路的数量。

输入的第二行给出四个整数a,b,k,g——a,b分别表示计算鸭的初始城市和目的城市;k表示计算鸭出发时刻;g表示道路管理员需要经过的城市数量。

输入的第三行给出g个整数xi​——表示道路管理员需要经过的城市编号。

接下来m行,每行3个整数ui​,vi​,ti​——表示从ui​至vi​需要用时ti​

2≤n≤103

2≤m≤104

1≤a,b,ui​,vi​≤n

0≤k,g≤103

1≤ti​≤103

输出格式:

输出一个整数——表示计算鸭从a城市到b城市的最短用时。

输入样例:

6 5
1 6 20 4
5 3 2 4
1 2 2
2 3 8
2 4 3
3 6 10
3 5 15 

输出样例:

21

输入样例:

8 9
1 5 5 5
1 2 3 4 5
1 2 8
2 7 4
2 3 10
6 7 40
3 6 5
6 8 3
4 8 4
4 5 5
3 4 23 

输出样例:

40

思路:

第一眼肯定能想到这就是一到最短路,但是他对你的路径添加了一些限制,这个时候就要思考一下这个限制怎么处理了(其实很简单)。因为他的限制只看我进入这条路的时间,所以我们只需要在跑最短路的时候,如果我进入这条路的时间在他的限制时间内时,我们只需要等到限制时间结束时再走就可以,这个时候我的进入时间就被拖到了限制时间结束的时间+1.其实到这题目就已经解决了,我们只需要提前把从一个城市到另一个城市的路的限制时间段算出来就行

我们只要处理一下最短路的时候两个点now到to的路上管理员有没有经过就行了,经过了就变成管理员走后那一秒就可以了

//转载自HXD徐先生

//链接:PTA 道路管制-CSDN博客

AC代码:

#include <bits/stdc++.h>

using namespace std;
#define int long long
#define endl '\n'
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
const int N = 1e5 + 5;
const int mod = 10086;
const int inf = 0x3f3f3f3f3f3f3f3f;
int n, m, k;
int g[N];
int l[1500][1500];
int r[1500][1500];
int mp[1500][1500];
int head[N * 4];
int vis[N * 4];
int dis[N * 4];
struct node {
    int u, v, val;
} edge[N * 4];
int cnt = 0;

void add(int u, int v, int val) {
    edge[cnt] = {head[u], v, val};
    head[u] = cnt++;
}

void dfs(int x) {
    priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> q;
    memset(dis, 0x3f, sizeof dis);
    dis[x] = k ;
    q.push({dis[x], x});
    while (!q.empty()) {
        int now = q.top().second;
        q.pop();
        if (vis[now])continue;
        vis[now] = 1;
        for (int i = head[now]; ~i; i = edge[i].u) {
            int to = edge[i].v;
            int w = edge[i].val;
            int time = dis[now];
            if (time >= l[now][to] && time <= r[now][to]) {//判断城管有没有在这两个点这个时间经过,经过就变成结束时间
                time = r[now][to] + 1;
            }
            if (dis[to] > time + w) {
                dis[to] = time + w;
                q.push({dis[to], to});
            }
        }
    }
}

signed main() {
    memset(head, -1, sizeof head);
    memset(vis, 0, sizeof vis);
    cin >> n >> m;
    int a, b, g1;
    cin >> a >> b >> k >> g1;
    for (int i = 0; i < g1; i++) {
        cin >> g[i];
    }
    for (int i = 0; i < m; i++) {
        int u, v, w;
        cin >> u >> v >> w;
        mp[u][v] = mp[v][u] = w;
        add(u, v, w);
        add(v, u, w);
    }
    int time = 0;
    for (int i = 1; i < g1; i++) {
        l[g[i - 1]][g[i]] = l[g[i]][g[i - 1]] = time;//处理城管从i-1点到i的最短时间
        time += mp[g[i - 1]][g[i]];
        r[g[i - 1]][g[i]] = r[g[i]][g[i - 1]] = time - 1;//处理城管从i-1点到i的最长时间
    }
    dfs(a);
    cout << dis[b] - k;
    return 0;
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值