Leetcode 5905. 到达目的地的第二短时间

城市用一个 双向连通 图表示,图中有 n 个节点,从 1 到 n 编号(包含 1 和 n)。图中的边用一个二维整数数组 edges 表示,其中每个 edges[i] = [ui, vi] 表示一条节点 ui 和节点 vi 之间的双向连通边。每组节点对由 最多一条 边连通,顶点不存在连接到自身的边。穿过任意一条边的时间是 time 分钟。

每个节点都有一个交通信号灯,每 change 分钟改变一次,从绿色变成红色,再由红色变成绿色,循环往复。所有信号灯都 同时 改变。你可以在 任何时候 进入某个节点,但是 只能 在节点 信号灯是绿色时 才能离开。如果信号灯是  绿色 ,你 不能 在节点等待,必须离开。

第二小的值 是 严格大于 最小值的所有值中最小的值。

例如,[2, 3, 4] 中第二小的值是 3 ,而 [2, 2, 4] 中第二小的值是 4 。
给你 n、edges、time 和 change ,返回从节点 1 到节点 n 需要的 第二短时间 。

注意:

你可以 任意次 穿过任意顶点,包括 1 和 n 。
你可以假设在 启程时 ,所有信号灯刚刚变成 绿色 。
 

示例 1: 

输入:n = 5, edges = [[1,2],[1,3],[1,4],[3,4],[4,5]], time = 3, change = 5
输出:13
解释:
上面的左图展现了给出的城市交通图。
右图中的蓝色路径是最短时间路径。
花费的时间是:
- 从节点 1 开始,总花费时间=0
- 1 -> 4:3 分钟,总花费时间=3
- 4 -> 5:3 分钟,总花费时间=6
因此需要的最小时间是 6 分钟。

右图中的红色路径是第二短时间路径。
- 从节点 1 开始,总花费时间=0
- 1 -> 3:3 分钟,总花费时间=3
- 3 -> 4:3 分钟,总花费时间=6
- 在节点 4 等待 4 分钟,总花费时间=10
- 4 -> 5:3 分钟,总花费时间=13
因此第二短时间是 13 分钟。      
示例 2:

输入:n = 2, edges = [[1,2]], time = 3, change = 2
输出:11
解释:
最短时间路径是 1 -> 2 ,总花费时间 = 3 分钟
最短时间路径是 1 -> 2 -> 1 -> 2 ,总花费时间 = 11 分钟
 

提示:

2 <= n <= 104
n - 1 <= edges.length <= min(2 * 104, n * (n - 1) / 2)
edges[i].length == 2
1 <= ui, vi <= n
ui != vi
不含重复边
每个节点都可以从其他节点直接或者间接到达
1 <= time, change <= 103

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/second-minimum-time-to-reach-destination
 

解法:

在许久没有写bfs之后,终于在题解评论中找到一个容易懂的代码。本题是类似权值为1的单源最短路径问题,可以用bfs,本题求的是次短路径,在bfs中节点被第二次访问到的路径大小>=第一次访问的路径大小。故节点1到节点n的次短路径就是节点n被第一次访问完后,再次被访问同时路径大于第一次被访问。每个点存储最短路径值与次短路径值。侵权删。

class Solution {
public:
	int secondMinimum(int n, vector<vector<int>>& edges, int time, int change) {
		vector<vector<int>> adj(n);
		for (auto edge : edges)
		{
			adj[edge[0] - 1].push_back(edge[1] - 1);
			adj[edge[1] - 1].push_back(edge[0] - 1);
		}
		vector<bool> vis(n);
		vector<vector<int> >d(n);//每个vector只存储两个值
		d[0].push_back(0);
		queue<int> q;
		q.push(0);
		int step = 0;//经过的边数
		while (!q.empty())
		{
			step++;
			int sz = q.size();
			while (sz--)
			{
				int u = q.front();
				q.pop();
				for (int v : adj[u])
				{
					if (d[v].empty()||(d[v].size()<2 && d[v][0]<step))//最短路径||次短路径
					{
						d[v].push_back(step);
						q.push(v);
					}
				}
                if(d[n-1].size()==2)break;
			}
            if(d[n-1].size()==2)break;
		}
		int ans = 0;
		for (int i = 0; i < d[n - 1][1]; i++)
		{
			ans += time;
			if (i<d[n - 1][1]-1 && ans / change & 1)
			{
				ans = ans - (ans%change) + change;
			}
		}
		return ans;
	}
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值