[leetcode]2045到达目的地的第二短时间,广搜

题意

给出一个双向连通图也就是无向图,用edges[i]=[ui,vi]表示顶点u和v连通并且每两点不会有多条边,穿过任意边的时间都是time分钟,那就说明建图不用在意边长,本题求的是次短路,但因为边长相同可能又不算很难,可是它多了一个change变量可能又不简单,这里默认每个顶点都有红绿灯,开始时刻全部灯都是绿色,每change分钟都会红绿切换。
题目说了绿灯的时候不能在节点等待必须离开,刚开始做的时候误解它的意思,以为在红灯的时候就必须停车,但其实是红灯且在节点里面才停车等待。

换句话说,城市只有这一辆车,即便是红灯,前方也没车拦住你靠近红绿灯的路口,只要在边上,只要没到达节点,不管绿灯还是红灯直接冲(误)!

思路

广度优先搜索

边长相等就很适合用广搜做,甚至不需要在搜索的时候就开始用time去计算时间,等价于求次短路所经过的顶点个数。可以当作边长等于1,得到次短路径后再求次短时间,但题目给的二维数组edges不方便广搜,重写一个二维数组保存每个顶点相邻的点,用数组flag标记已到达的点,因为求的是严格的次短,可以将标记扩展为二维数组,表示每个顶点第一次到达的时间和第二次到达的时间,初始化为正无穷表示未到达。
有标记,有图,还差队列。这里的队列不能只存一个int变量,需要存进入队列的顶点编号,还要存已经过的步长(距离),首次到达顶点可标记为最短距离,但第二次到达顶点必须严格大于最短距离才能当作次小距离

时间的计算

理解到什么情况才会停车后,公式就出来了:用ans保存已花的时间,flag[n][1]表示次短路经过的顶点个数(不包含起点,也可以理解成次短路的边长),每走一条边都需要花time分钟,每过一个顶点都要统计一下等待红灯的时间:到达上一个顶点后,如果遇到红灯的话,红灯还会维持的时间。
遇到红灯可以表示为: a n s % ( 2 ∗ c h a n g e ) > c h a n g e ans\%(2*change)>change ans%(2change)>change。这个比较好理解,就是总时间每change分钟切换一次红绿灯,切换奇数次就是红灯。
红灯维持时间为 2 ∗ c h a n g e − a n s % ( 2 ∗ c h a n g e ) 2*change - ans\%(2*change) 2changeans%(2change)。因为2*change为一个循环,下次绿灯的时间与红灯已经维持的时间是互补的。

代码

class Solution {
public:
    int secondMinimum(int n, vector<vector<int>>& edges, int time, int change) {
        vector<vector<int>> g(n+1);
        for(auto &e: edges){
            g[e[0]].emplace_back(e[1]);
            g[e[1]].emplace_back(e[0]);
        }
        vector<vector<int>> flag(n+1,vector<int>(2,INT_MAX));
        queue<pair<int,int>> q;//左为位置,右为步长
        q.push({1,0});//起点1的步长为0
        flag[1][0]=0;
        while(!q.empty()){
            auto [x,len]=q.front();
            q.pop();
            for(int i:g[x]){
                if(len+1<flag[i][0]){
                    flag[i][0]=len+1;
                    q.push({i,len+1});
                }else if(len+1<flag[i][1] &&len+1>flag[i][0]){//严格>flag[i][0]
                    flag[i][1]=len+1;
                    q.push({i,len+1});
                }
            }
        }
        int ans = 0;
        int mod = 2*change;
        for(int i = 0;i < flag[n][1]; ++i){
            if(ans%mod >= change){
                ans += mod - ans%mod;
            }
            ans += time;
        }
        return ans;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值