【LeetCode】743. Network Delay Time(C++)
題目:
There are N
network nodes, labelled 1
to N
.
Given times
, a list of travel times as directed edges times[i] = (u, v, w)
, where u
is the source node, v
is the target node, and w
is the time it takes for a signal to travel from source to target.
Now, we send a signal from a certain node K
. How long will it take for all nodes to receive the signal? If it is impossible, return -1
Note:
N
will be in the range[1, 100]
.K
will be in the range[1, N]
.- The length of
times
will be in the range[1, 6000]
. - All edges
times[i] = (u, v, w)
will have1 <= u
,v <= N
and1 <= w <= 100
.
理解:
單源最短路徑問題。想到的就是課本上講的Dijkstra演算法。這篇文章寫的比較清楚,不記得的話可以參考一下。https://www.cnblogs.com/skywang12345/p/3711514.html
實現1:
首先給個王道書裡的方法
closed[]
:已經找到了到其他點的最短路徑
Min[]
:當前的到所有點的最短路徑
注意外迴圈共N次,每次先找到未加入集合的最小距離的點,然後從該點出發更新dist集合。王道書中給的思路是N-1次迴圈,這種情況下初始的dist就應該是K到其他點的距離,而不是INT_MAX。
class Solution {
public:
int networkDelayTime(vector<vector<int>>& times, int N, int K) {
int res = 0;
vector<vector<int>> adjacency(N + 1, vector<int>(N + 1, -1));
for (auto edge : times)
adjacency[edge[0]][edge[1]] = edge[2];
vector<int> dist(N + 1, INT_MAX);
dist[K] = 0;
vector<bool> closed(N + 1,false);
for (int i = 1; i<=N; ++i) {
int k = -1;
for (int j = 1; j<=N; ++j)
//find the smallest distance in the set of unfounded vertices
if (!closed[j] && (k == -1 || dist[k]>dist[j]))
k = j;
closed[k] = true;
for (int j = 1; j<=N; ++j)
if (adjacency[k][j] != -1 && dist[k] + adjacency[k][j]<dist[j])
dist[j] = adjacency[k][j] + dist[k];
}
for (int i = 1; i <= N; ++i) {
res = max(res, dist[i]);
}
return res == INT_MAX ? -1 : res;
}
};
實現2:
下面這種方法和上面實現略有差別。 這裡用queue避免了每次都要通過迴圈掃描所有的closed,而是把上輪迴圈更新過距離的節點進行考慮。注意演算法裡的visited並不是已經尋找到最短路徑的點集合,只是防止多次加入佇列。這裡的隊列表示了這一輪更新過距離的節點,因為他們的距離更新了,因此可能導致其他從他們出發的結點距離更新,所以需要加入佇列進行下一次的判斷。這裡的收斂性依靠的是演算法自身的性質,而不是程式的判斷。當沒有結點的距離更新的時候,就停止了。
class Solution {
public:
int networkDelayTime(vector<vector<int>>& times, int N, int K) {
int res = 0;
vector<vector<int>> adjacency(N + 1, vector<int>(N + 1, -1));
for (auto edge : times)
adjacency[edge[0]][edge[1]] = edge[2];
queue<int> q{ {K} };
vector<int> dist(N + 1, INT_MAX);
dist[K] = 0;
while (!q.empty()) {
//visited here is only for insert v in the queue, which means that dist[v] is updated, maybe some other dist should be update
unordered_set<int> visited;
for (int i = q.size(); i > 0; --i) {
int u = q.front();
// printf("%d ", u);
q.pop();
for (int v = 1; v <= N; ++v) {
if (adjacency[u][v] != -1 && (dist[u] + adjacency[u][v] < dist[v])) {
if (!visited.count(v)) {
visited.insert(v);
q.push(v);
}
dist[v] = adjacency[u][v] + dist[u];
}
}
}
// printf("\n");
}
for (int i = 1; i <= N; ++i) {
res = max(res, dist[i]);
}
return res == INT_MAX ? -1 : res;
}
};
實現3:
突然發現基於priority_queue的實現其實和上面差不多,只是priority_queue的top是優先順序最高的元素。 來一段別人寫好的程式碼吧。
class Solution {
public:
int networkDelayTime(vector<vector<int>>& times, int N, int K) {
// Dijkstra algorithm
vector<int> distance(N, INT_MAX);
distance[K - 1] = 0;
// use an adjacent linked list to represent the graph
unordered_map<int, unordered_map<int, int>> adj;
for (auto& e : times) adj[e[0] - 1][e[1] - 1] = e[2];
// {distance, vertex} as an element added into the priority queue
// we don't have decrease_key opearation
auto comp = [](const pair<int, int>& lhs, const pair<int, int>& rhs) {return lhs.first > rhs.first; };
priority_queue<pair<int, int>, vector<pair<int, int>>, decltype(comp)> q(comp);
q.push({ 0, K - 1 });
// when q is not empty
while (!q.empty())
{
auto ele = q.top();
int src = ele.second;
q.pop();
for (auto& edge : adj[src])
{
int des = edge.first;
// relaxation
if (distance[src] + adj[src][des] < distance[des])
{
distance[des] = distance[src] + adj[src][des];
// if we successfully update the distance, push it into the priority queue
// for the old value in the priority_queue, it will never successfully update the distance
// hence, it's okay to have duplicates
q.push({ distance[des], des });
}
}
}
// find the maximum time we need to wait, if it's INT_MAX, some nodes must be not reachable
int ans;
for (auto& wait : distance) ans = max(ans, wait);
return ans == INT_MAX ? -1 : ans;
}
};
實現4:
基於Bellman-Ford演算法。 Bellman - ford演算法是求含負權圖的單源最短路徑的一種演算法,效率較低,程式碼難度較小。其原理為連續進行鬆弛,在每次鬆弛時把每條邊都更新一下,若在n-1次鬆弛後還能更新,則說明圖中有負環,因此無法得出結果,否則就完成。–Bellman-Ford演算法
class Solution {
public:
int networkDelayTime(vector<vector<int>>& times, int N, int K) {
vector<int> dist(N + 1, INT_MAX);
dist[K] = 0;
for (int i = 0; i < N; i++) {
for (vector<int> e : times) {
int u = e[0], v = e[1], w = e[2];
if (dist[u] != INT_MAX && dist[v] > dist[u] + w) {
dist[v] = dist[u] + w;
}
}
}
int maxwait = 0;
for (int i = 1; i <= N; i++)
maxwait = max(maxwait, dist[i]);
return maxwait == INT_MAX ? -1 : maxwait;
}
};
感覺。。都差不多啊。。 不太舒服。。不會又要感冒吧 這道題應該是目前為止,easy裡花時間最多的了。