题目
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 have 1 <= u, v <= N and 1 <= w <= 100.
Example 1:
Input: [[2,1,1],[2,3,1],[3,4,1]]
4
2
Output: 2
算法思路
这周学习广度优先搜索法(BFS)在图论研究中的应用,BFS特别适用于解决一些图中最短路径的问题。这道题其实也是一个最短路径的问题,求所有节点都接受到信息所需的延迟时间,其实就是求所有点最短路径中最远的一个的距离。
由于图中点与点的距离不是固定的,单纯的BFS不好解决问题,考虑用BFS的一个变种dijkstra算法。
Dijkstra算法采用的是一种贪心的策略,声明一个最短路径数组dist来保存当前源点到各个顶点的最短距离和一个保存已经找到了最短路径的顶点的集合:visited。
- 初始化时,原点 s 的最短路径被赋为 0,存入一个小端的优先级队列queue中 。其他点最短路径赋值无穷。
- 循环从queue中取一个点v,即当前没访问过的点中dist值最小的点,遍历这个点能到达的所有点,并且判断通过该顶点到达其他点的路径长度是否比源点直接到达短,如果是,那么就更新这些顶点在dist中的值。
伪代码:
for all u ∈ V :
dist(u) = ∞
dist(s) = 0
H = makequeue(V ) //以dist为键,以顶点号值的小端优先队列)
while H is not empty:
u = deletemin(H) //取dist最小的顶点
for all edges (u,v) ∈ E: //遍历相应的边
if dist(v) > dist(u) + l(u,v):
dist(v) = dist(u) + l(u,v)
decreasekey(H,v)//根据dist的更新变更队列的排序
需要注意如果存在多个连通分支,dijkstra算法执行完后,判断是否存在没被搜索过的点(即网络不可到达)而返回-1。
C++代码
class Solution {
//以距离为键,顶点号为值的pair
struct mypair
{
pair<int, int> x;
mypair(int key, int value) {
x = make_pair(key, value);
}
bool operator < (const mypair& a) const{
return x.first > a.x.first;
}
};
public:
int networkDelayTime(vector<vector<int> >& times, int N, int K) {
//将边的集合根据起点分类
vector<vector<pair<int, int> > > graph;
for (int i = 0; i < N; ++i)
{
graph.push_back(vector<pair<int, int> >());
}
for (int i = 0; i < times.size(); ++i)
{
graph[times[i][0]-1].push_back(make_pair(times[i][1], times[i][2]));
}
//算法主体
priority_queue<mypair> willBeVisitedNodes;
int dist[N];
bool visited[N] = {false};
for (int i = 0; i < N; ++i)
{
dist[i] = INT_MAX;
}
dist[K-1] = 0;
for (int i = 0; i < N; ++i)
{
willBeVisitedNodes.push(mypair(dist[i],i));
}
while(!willBeVisitedNodes.empty()){
mypair now = willBeVisitedNodes.top();
willBeVisitedNodes.pop();
if (visited[now.x.second]) {
continue;
}
visited[now.x.second] = true;
for (int i = 0; i < graph[now.x.second].size(); ++i)
{
if (dist[graph[now.x.second][i].first-1] == INT_MAX || dist[graph[now.x.second][i].first-1] > dist[now.x.second] + graph[now.x.second][i].second)
{
dist[graph[now.x.second][i].first-1] = dist[now.x.second] + graph[now.x.second][i].second;
willBeVisitedNodes.push(mypair(dist[graph[now.x.second][i].first-1],graph[now.x.second][i].first-1));
}
}
}
//寻找最中路径最长的点,同时判断是否是连通图
int result = 0;
for (int i = 0; i < N; ++i)
{
if (dist[i] > result)
{
result = dist[i];
}
if (dist[i] == INT_MAX){
return -1;
}
}
return result;
}
};