[LeetCode]2045. BFS 求第二短的路徑
阿新 • • 發佈:2021-11-19
本文介紹了一種使用BFS求解LeetCode第2045題的方法。
,如果有兩條最短的不同路徑長度都為x,那麼我還需要繼續求得一個大於x的第二短路徑。既然是等邊長圖中,求最短路徑我們可以使用BFS。
一、摘要
本文介紹了一種使用BFS求無向圖中第二短的距離的演算法,本文演算法參考自Python3 BFS找出第二短路徑。通過使用BFS求出題目中給出的路徑圖(無向聯通圖)從節點1到節點n的第二短的路徑,再根據路徑長度計算出需要耗費的時間。其實在LeetCode官網本題目的題解欄目下已經有很多優秀的題解了,本文除了是使用C++與其他題解有些許不同外無任何優勢。還是建議讀者閱讀其他高贊題解。
二、題解
由於給給節點上紅燈、綠燈的亮暗是一致的,因此將各節點間的邊長視作1,只要求出從節點0
到節點n-1
經過的路徑長度即可得到總的耗費時間。
因此本題就變成了求節點0
到節點n-1
的第二短的長度。
需要注意的是,我們要求的是絕對的第二短的路徑
使用一個佇列queue<pair<int, int>>
記錄所搜到的節點id
和從節點0到該節點id的耗時
。
為了求第二短的距離因此我們是用兩個陣列vector<int> first
和vector<int> second
分別記錄節點0
到節點id
的第一、二短耗時(初始時都設為最大值,在C++中即為INT_MAX)。
在使用佇列進行bfs演算法時:
- 如果下一個可能要入佇列的
節點n_id
需要的耗時n_time
小於first[n_id]
節點0
到節點n_id
的最短耗時為n_time,需要入隊pair<int,int>(n_id, n_time)``。 - 如果下一個可能要入佇列的
節點n_id
需要的耗時n_time
等於first[n_id]
,那麼說明存在重複的 從節點0
到節點n_id
的耗時相同、但路徑不同 的最短耗時,此時不需要入隊; - 如果下一個可能要入佇列的
節點n_id
需要的耗時n_time
大於first[n_id]
,且小於second[n_id]
,那麼說明節點0
到節點n_id
的第二短耗時為n_time,需要入隊pair<int, int>(n_id, n_time)
。 - 如果下一個可能要入佇列的
節點n_id
耗時n_time
大於等於second[n_id]
,那麼說明存在重複的 從節點0
到節點n_id
的耗時相同、但路徑不同 的第二短耗時、或者這是第三短的耗時,此時不需要入隊;
程式碼如下:
class Solution {
public:
// 圖的節點
struct Node{
int idx; // 節點id
vector<int> neighbor; // 相鄰的節點id
Node(int i):idx(i){}
};
// 根據此時的時間now計算經過一條邊,到達下一個節點的時間
int getNextTime(int now, int time, int change){
if((now/change)%2==0){
now += time;
}else{
now += (change - now%change)+time;
}
return now;
}
int secondMinimum(int n, vector<vector<int>>& edges, int time, int change) {
nodes_.resize(n);
for(int i=0; i<n; i++){
nodes_[i] = new Node(i);
}
// 建圖
for(int i=0; i<edges.size(); i++){
int a = edges[i][0] - 1;
int b = edges[i][1] - 1;
nodes_[a]->neighbor.push_back(b);
nodes_[b]->neighbor.push_back(a);
}
queue<pair<int, int>> que;
vector<int> first(n, INT_MAX); // first記錄到達節點i最短的耗時
vector<int> second(n, INT_MAX); // second記錄到達節點i第二短的耗時
que.push(pair<int, int>(0,0)); // 將(0,0)入隊,表示達到節點0的耗時為0
while(que.empty()==false){
int id = que.front().first;
int now = que.front().second;
que.pop();
for(int i=0; i<nodes_[id]->neighbor.size(); i++){
int n_id = nodes_[id]->neighbor[i];
int n_time = getNextTime(now, time, change);
if(n_id==n-1){ // 如果是第n個節點
if(first[n_id]==INT_MAX){ // 第一次到達節點n-1,更新first,且pair<int,int>(n_id,n_time)入隊
first[n_id] = n_time;
que.push(pair<int, int>(n_id, n_time));
}else if(n_time>first[n_id] && second[n_id]==INT_MAX){ // 到達節點n-1的第二短距離,返回答案
second[n_id] = n_time;
return n_time;
}
}else{
if(first[n_id]==INT_MAX){ // 第一次到達節點n_id,更新first,且pair<int,int>(n_id,n_time)入隊
first[n_id] = n_time;
que.push(pair<int, int>(n_id, n_time));
}else if(n_time>first[n_id] && second[n_id]==INT_MAX){ // 到達節點n-1的第二短的距離,更新second,且pair<int,int>(n_id,n_time)入隊
second[n_id] = n_time;
que.push(pair<int, int>(n_id, n_time));
}
}
}
}
return 0;
}
vector<Node*> nodes_;
};
複雜度分析:
- 時間複雜度:O(n+m)
- 空間複雜度:O(n+m)
其中n為節點個數,m為邊個數