题目(困难)
题目太长放链接
力扣2045——到达目的地的第二短时间
思路
不是最优但好理解;
时间其实和路径长度相关,转化为求次短路径;
时间与路径长度有关,如果当前时间处于红灯,就等到绿灯,然后加上每段路的时间,所以只要求次短路径;
用BFS求最短路径,采用类似层序遍历的方法,每次步长+1,得到最短和次短路径长,并由步长得到时间。
由于时间复杂度太高需要剪枝,对于次短路径,其实无非两种,minstep+1,minstep+2;
其中minstep+2一定存在,就是多一段往返,而minstep+1不一定存在,需要不重复的多走一步;
无论哪种情况,每个节点访问次数不会超过2次,所以统计访问次数进行剪枝;
另外用set去重的保存下一层的节点们,剪掉同层多个节点访问下一层同一节点的多余情况;
代码
class Solution {
public:
int t, c;
int needtime(int step) {
int at = 0;
for(int i = 1; i <= step; i++) {
if((at / c) % 2) {
at += (at / c + 1) * c - at;
}
at += t;
}
return at;
}
int secondMinimum(int n, vector<vector<int>>& edges, int time, int change) {
vector<vector<int>> hash(n+1);
vector<int> vis(n+1);
vis[1] = 1;
t = time, c = change;
for(auto edge : edges) {
int a = edge[0], b = edge[1];
hash[a].push_back(b);
hash[b].push_back(a);
}
int step = 0, minstep = 0, ansstep = 0;
int mintime = 0, anstime = 0;
queue<int> q;
q.push(1);
while(!q.empty()) {
int nextn = q.size();
step++;
unordered_set<int> nextfloor; //下一层要遍历的节点,set去重
while(nextn--) { //层序遍历
int now = q.front();
q.pop();
for(auto next : hash[now]) {
if(next == n && minstep == 0) minstep = step;
else if(next == n && minstep && step > minstep) ansstep = step;
if(!nextfloor.count(next)) {
if(++vis[next] < 3) {
nextfloor.insert(next);
q.push(next);
}
}
}
}
if(ansstep) return needtime(ansstep);
}
return 0;
}
};