PTA 道路管制

文章介绍了一个涉及道路管理员道路管控的最短路径问题,要求在管理员活动期间找到鸭子从a到b的最小行驶时间。解题需考虑管理员行走路线对时间的影响。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

乌拉乌拉国有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

 题意大概

就是管理员在某些时间内会走一些路,在他走那段路的时间内,我们不能走那条路,问我们最少要多少时间,并且给出的管理员的路只会走两点直连的路。

解题思路

首先我们要明确的是管理员在进入某条道路的时候是哪个时间段道路会被封锁:

假设:管理员一开始从3号点走向5号点需要花费15的时间,那么管理员在3号点的时间就是0

5号点的时间就是15,而在0->14的时间内则是我们不能进入当前道路的时间段。所以只要记录管理员走到每段路的时间点,在最短路里判断一下当前跑的路,若为管理员会走的路,再判断一下时间范围即可

坑点

这题我一开始的思路的记录管理员到达每个点的时间点,但是这题管理员会走到重复的点!!!!

所以一直wa一个点 QAQ 。

代码 

#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
const ll N = 2e3 + 10, M = 2e4 + 10;
ll n, m, k, st, ed, g;
ll num, idx;
ll ti[2][N][N];//第一维分别表示起点和终点,第二第三维表示相连的两点的边
vector<ll> ve;
ll dist[M], head[M], vis[M];
map<ll, map<ll, ll>> mp;//标记当前的边是否为管理员会走的边
struct node {
    ll ne, to, val;
} a[M];

void add(ll ne, ll to, ll val) {//链前(应该没人不懂吧)
    a[idx].ne = head[ne];
    a[idx].to = to;
    a[idx].val = val;
    head[ne] = idx++;
}

void bfs(ll xx, ll t) { //最短路
    priority_queue<pair<ll, ll>, vector<pair<ll, ll>>, greater<>> q;
    memset(dist, 0x3f, sizeof dist);
    memset(vis, 0, sizeof vis);
    dist[xx] = t;//记初始点为初始时间
    q.push({t, xx});
    while (!q.empty()) {
        ll x = q.top().second;
        q.pop();
        if (vis[x])continue;
        vis[x] = 1;
        for (ll i = head[x]; ~i; i = a[i].ne) {
            ll to = a[i].to;
            ll val = a[i].val;
            if (mp[x].count(to) && dist[x] >= ti[0][x][to] && dist[x] < ti[1][x][to]) {//判断是否为管理员会走的路,并且判断时间
                if (dist[to] > ti[1][x][to] + val) {
                    dist[to] = ti[1][x][to] + val;
                    q.push({dist[to], to});
                }
            } else if (dist[to] > dist[x] + val) {
                dist[to] = dist[x] + val;
                q.push({dist[to], to});
            }
        }
    }
}

int main() {
    cin >> n >> m;
    idx = 0;
    memset(head, -1, sizeof head);
    cin >> st >> ed >> k >> g;
    for (ll i = 0; i < g; i++) {
        cin >> num;
        if (i)mp[num][ve.back()] = 1;//标记这条路为管理员会走的路
        ve.push_back(num);
    }
    for (ll i = 0; i < m; i++) {
        ll u, v, w;
        cin >> u >> v >> w;
        if (mp[u].count(v) || mp[v].count(u))mp[u][v] = w, mp[v][u] = w;//更新管理员会走的路所需的时间
        add(u, v, w), add(v, u, w);//存双向边
    }
    if (g > 1) {  //防止vecrtor越界
        ti[0][ve[0]][ve[1]] = 0;
        ti[1][ve[0]][ve[1]] = mp[ve[0]][ve[1]];
        ti[0][ve[1]][ve[0]] = 0;
        ti[1][ve[1]][ve[0]] = mp[ve[1]][ve[0]];
    }
    for (ll i = 2; i < ve.size(); i++) {//记录每条路的封闭时间
        //注意边是双向的所以我们封闭时间也要存双向的,我们所走的路径不一定是与管理员同方向的
        ti[0][ve[i - 1]][ve[i]] = ti[1][ve[i - 2]][ve[i - 1]];
        ti[1][ve[i - 1]][ve[i]] = ti[0][ve[i - 1]][ve[i]] + mp[ve[i - 1]][ve[i]];
        ti[0][ve[i]][ve[i - 1]] = ti[0][ve[i - 1]][ve[i]];
        ti[1][ve[i]][ve[i - 1]] = ti[1][ve[i - 1]][ve[i]];
    }
    bfs(st, k);
    cout << dist[ed] - k << endl;//注意减去初始时间才是花费的时间
}

 并附上我之前想法wa一个点的想法QAQ

#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
const ll N = 2e5 + 10;
const ll inf = 0x3f3f3f3f3f3f3f3f;
ll n, m, k, st, ed, g;
ll num, idx;
ll vis[N];
map<ll, ll> ti;
vector<ll> ve;
ll dist[N];
ll head[N];
ll mp[1010][1010];
struct node {
    ll ne, mid, val;
} a[N];

void add(ll ne, ll mid, ll val) {
    a[idx].ne = head[ne];
    a[idx].mid = mid;
    a[idx].val = val;
    head[ne] = idx++;
}

void bfs(ll xx, ll t) {
    priority_queue<pair<ll, ll>, vector<pair<ll, ll>>, greater<>> q;
    for (ll i = 1; i <= n; i++)dist[i] = inf;
    memset(vis, 0, sizeof vis);
    dist[xx] = t;
    q.push({t, xx});
    while (!q.empty()) {
        ll x = q.top().second;
        q.pop();
        if (vis[x])continue;
        vis[x] = 1;
        for (ll i = head[x]; ~i; i = a[i].ne) {
            ll mid = a[i].mid;
            ll val = a[i].val;
            if (dist[mid] > dist[x] + val) {
                if (mp[x][mid] && dist[x] >= min(ti[mid], ti[x]) && dist[x] <= max(ti[mid], ti[x])) {
                    dist[mid] = max(ti[mid], ti[x]) + val;
                } else {
                    dist[mid] = dist[x] + val;
                }
                q.push({dist[mid], mid});
            }
        }
    }
}

int main() {
    cin >> n >> m;
    idx = 0;
    memset(head, -1, sizeof head);
    cin >> st >> ed >> k >> g;
    for (ll i = 0; i < g; i++) {
        cin >> num;
        if (i)mp[num][ve.back()] = 1;
        ve.push_back(num);
    }
    for (ll i = 0; i < m; i++) {
        ll u, v, w;
        cin >> u >> v >> w;
        if (mp[u][v] || mp[v][u])mp[u][v] = w, mp[v][u] = w;
        add(u, v, w), add(v, u, w);
    }
    for (ll i = 1; i < ve.size(); i++) {
        ti[ve[i]] = mp[ve[i - 1]][ve[i]] + ti[ve[i - 1]];
    }
    bfs(st, k);
    cout << dist[ed] - k << endl;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值