地址:https://leetcode.com/problems/network-delay-time
题目:
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
周六早起+没午觉+上网球课的我,晚上脑子就和炸了一样。并没有看懂这个题给的times是什么玩意,想了半天才明白,给的是每条边的起点、终点和权值。
呵呵,然后Dijkstra算法怎么实现还是不会。。。首先要把给的输入转成矩阵形式,然后再进行比较更方便。但是不知道怎么实现啊。。。嗯。。去看看别人怎么写的,发现很多人都用了priority_queue。。更懵逼了,还是先搞定最基础的
O
(
N
2
)
O(N^2)
O(N2)的算法吧。
实现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里花时间最多的了。