题目:
There are
N
network nodes, labelled1
toN
.
Giventimes
, a list of travel times as directed edgestimes[i] = (u, v, w)
, whereu
is the source node,v
is the target node, andw
is the time it takes for a signal to travel from source to target.
Now, we send a signal from a certain nodeK
. How long will it take for all nodes to receive the signal? If it is impossible, return-1
.
Note:
1.N
will be in the range[1, 100]
.
2.K
will be in the range[1, N]
.
The length oftimes
will be in the range[1, 6000]
.
All edgestimes[i] = (u, v, w)
will have1 <= u, v <= N
and1 <= w <= 100
.
解释:
无向图的最短路径:
Floyd算法可以算出图中所有节点之间的最短路径长度
Dijkstra算法只能求得某特定结点到其他所有结点的最短路径长度
这道题目是有向图,感觉可以用dfs做。
所有的结点都收到所需要的时间,就是每个结点都能收到的情况下,最迟收到信号的结点收到信号所需要的时间,如果有结点根本收不到信号那么就返回
解法参考《计算机考研机试指南的》p121 的Dijkstra算法解法。
python代码:
#邻接链表元素结构体
class E:
def __init__(self,time,nxt):
self.t=time
self.next=nxt
class Solution(object):
def networkDelayTime(self, times, N, K):
"""
:type times: List[List[int]]
:type N: int
:type K: int
:rtype: int
"""
#邻接链表,如果内层不是数字的话,不要轻易写成乘法
edge=[[] for _ in range(N+1)]
#距离向量,当mark[i]为True时,表示已经得到的最短路径长度,否则表示所有从结点K出发,经过已知的最短路径到达
#集合S中的某一点,再经过一条边到达结点i的最短距离
Dis=[-1]*(N+1)
Dis[0]=0
#是否属于集合S,S数组保存当前最短路径的集合
mark=[False]*(N+1)
for time in times:
a,b,c=time
tmp1=E(c,b)
edge[a].append(tmp1)
# tmp2=E(c,a)
# edge[b].append(tmp2)
#起点为K
Dis[K]=0
mark[K]=True
newP=K
#循环n-1次,寻找其他n-1个结点的最短路径
for i in range(1,N):
#遍历与新加入的结点直接相连的边
for j in range(len(edge[newP])):
#该边的另一个结点
tmpnext=edge[newP][j].next
tmpt=edge[newP][j].t
#若另一个结点也属于集合S,则跳过
if mark[tmpnext]==True:
continue
#若该点尚不可达到或者该点从新加入的结点经过一条边到达时比以往距离更短
if Dis[tmpnext]==-1 or Dis[tmpnext]>Dis[newP]+tmpt:
Dis[tmpnext]=Dis[newP]+tmpt
#K经过已知的最短路径到达集合S中的某一点,再经过一条边到达结点i的最短距离
_min=float('inf')
#遍历所有结点
for j in range(1,N+1):
#若其属于集合S,则跳过
if mark[j]==True:
continue
#若该结点还尚未到达
if Dis[j]==-1:
continue
if Dis[j]<_min:
_min=Dis[j]
newP=j#新加入的点暂定为该点
#加入到集合S中
mark[newP]=True
return -1 if -1 in Dis else max(Dis)
c++代码:
//邻接链表中的链表元素结构体
struct E
{
int next;//代表直接相邻的结点,注意这里next不是指针
int t;//代表改边的权重
};
class Solution {
public:
int networkDelayTime(vector<vector<int>>& times, int N, int K) {
//邻接链表
vector<vector<E>>edge(N+1,vector<E>());
//设已经确定了最短路径长度的结点所构成的集合为集合S
//标记,当mark[i]为true时,表示已经得到K到i的最短路径长度
vector<bool>mark(N+1,false);
//距离向量,mark[i]为true时,表示K到i的最短路径,否则表示从结点K出发到集合S中的某一点,再经过该点和i的连线到达i的距离
vector<int>Dis(N+1,-1);
//0结点不存在但是不能保持-1的值影响最终的结果
Dis[0]=0;
//构建邻接表
for(auto time:times)
{
int a=time[0],b=time[1],c=time[2];
E tmp;
tmp.next=b;
tmp.t=c;
edge[a].push_back(tmp);//由于是有向图,所以这里只需要写一个
}
//起点为K
Dis[K]=0;
mark[K]=true;
//集合S中新加入的结点为K
int newP=K;
//求其他N-1个结点的最短路径长度
for (int i=1;i<N+1;i++)
{
//遍历与新加入的结点newP相邻的所有结点
for(int j=0;j<edge[newP].size();j++)
{
int tmpnext=edge[newP][j].next;//该边的另一个结点
int tmpt=edge[newP][j].t;//该边的权重
//如果该结点已经在集合S中,表示已经求得K到tmpnext的最短路径
if(mark[tmpnext]==true)
continue;
//若该结点尚不可达或者通过newP可以使得到达该结点的路径更短
if(Dis[tmpnext]==-1 || Dis[tmpnext]>Dis[newP]+tmpt)
{
Dis[tmpnext]=Dis[newP]+tmpt;
}
}
//接下来要找一个新的结点加入集合S,也就是要找一个到K的距离最短的结点加入到S
int _min=INT_MAX;
//遍历所有结点
for(int j=1;j<N+1;j++)
{
//如果结点已经在S中,则跳过
if(mark[j]==true)
continue;
//如果该点仍不可到达,也跳过
if(Dis[j]==-1)
continue;
if (Dis[j]<_min)
{
_min=Dis[j];
newP=j;//姑且先让该点成为新加入的结点,反正后面还要更新。
}
}
//把newP加入集合S
mark[newP]=true;
}
if (count(Dis.begin(),Dis.end(),-1)!=0)
return -1;
else
return *max_element(Dis.begin(),Dis.end());
}
};
总结: