首先推荐博客:图论最短路径专题(力扣743、5888)_力扣 最短路径-CSDN博客
迪杰斯特拉算法:
太久没有做图论的题了,,临时抱佛脚。。
这道题可以转化为max{点x到点k的距离}。因为带权图(权值为正),无环,求最短路径的情况,迪杰斯特拉分为两个步骤:首先是初始化数组(G:二维数组,记录初始时刻点与点之间的距离,dist:每个点距k点的距离,visit:每个点是否已经确认距k点的距离)。第二部是一个大循环,即将n个点全部更新距k点的距离。再循环中,分为三个小步骤:第一点是寻找距k点距离最短的点(且该点距离k的距离还没有确定),第二点是将该点放入已知距k点距离的集合内(即visit[jj]=1),第三点是更新jj临近的那些点(距离k的距离还没有确定)距离k点的值。
参考PPT:
代码:
C++:
class Solution {
public:
int networkDelayTime(vector<vector<int>>& times, int n, int k) {
int inf=INT_MAX;
vector<vector<int>> G(n+1,vector<int>(n+1,inf));
vector<int> dist(n+1,inf);//k距离其他结点的距离
vector<int> visit(n+1,0);//结点x是否已经确定最短距离
int res=0;
/*初始化*/
int len=times.size();
for(int i=0;i<len;i++){
G[times[i][0]][times[i][1]]=times[i][2];
}
for(int i=1;i<=n;i++){
G[i][i]=0;
}
dist[k]=0;
/*正式迪杰斯特拉*/ //要更新n个结点
for(int i=1;i<=n;i++){
int min=INT_MAX;
int jj=-1;
/*找到距离k最短的距离*/
for(int j=1;j<=n;j++){
if(visit[j]==0 && dist[j]<min){
jj=j;
min=dist[j];
}
}
/*visit[]*/
if(jj==-1){return -1;}
visit[jj]=1;
res=max(res,min);
/*更新以jj为头结点的距离*/
for(int j=1;j<=n;j++){
if(G[jj][j]!=INT_MAX && visit[j]==0 && dist[j]>dist[jj]+G[jj][j]){
dist[j]=dist[jj]+G[jj][j];
}
}
}
return res;
}
};
Python:
class Solution:
def networkDelayTime(self, times: List[List[int]], n: int, k: int) -> int:
G=[[float("inf") for _ in range(n+1)] for _ in range(n+1)]
dist=[float("inf")]*(n+1)
visit=[0]*(n+1)
res=0
len_=len(times)
for i in range(len_):
G[times[i][0]][times[i][1]]=times[i][2]
for i in range(1,n+1):
G[i][i]=0
dist[k]=0
for i in range(1,n+1):
min_=float("inf")
jj=-1
for j in range(1,n+1):
if visit[j]==0 and dist[j]<min_:
jj=j
min_=dist[j]
if jj==-1:
return -1
visit[jj]=1
res=max(res,min_)
for j in range(1,n+1):
if G[jj][j]!=float("inf") and visit[j]==0 and dist[j]>dist[jj]+G[jj][j]:
dist[j]=dist[jj]+G[jj][j]
return res
Floyd算法:
Floyd算法不能有环,允许有带负权值的边,但不允许有包含带负权值的边组成的回路
采用动态规划的思想,用结点k来更新结点i,j之间的距离:G[i][j]=?=G[i][k]+G[k][j],用三层for循环来实现参考PPT:
代码:
C++:
class Solution {
public:
int networkDelayTime(vector<vector<int>>& times, int n, int k) {
int inf=INT_MAX/2;
vector<vector<int>> G(n+1,vector<int>(n+1,inf));
/*初始化*/
int len=times.size();
for(int i=0;i<len;i++){
G[times[i][0]][times[i][1]]=times[i][2];
}
for(int i=1;i<=n;i++){
G[i][i]=0;
}
for(int k=1;k<=n;k++){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(G[i][j]>G[i][k]+G[k][j]){
G[i][j]=G[i][k]+G[k][j];
}
}
}
}
/*求结果*/
int res=0;
for(int i=1;i<=n;i++){
res=max(res,G[k][i]);
}
if(res==INT_MAX/2){return -1;}
return res;
}
};
Python:
class Solution:
def networkDelayTime(self, times: List[List[int]], n: int, k: int) -> int:
G=[[float("inf") for _ in range(n+1)] for _ in range(n+1)]
len_=len(times)
for i in range(len_):
G[times[i][0]][times[i][1]]=times[i][2]
for i in range(1,n+1):
G[i][i]=0
for kk in range(1,n+1):
for i in range(1,n+1):
for j in range(1,n+1):
if G[i][j]>G[i][kk]+G[kk][j]:
G[i][j]=G[i][kk]+G[kk][j]
res=0
for i in range(1,n+1):
res=max(res,G[k][i])
if res==float("inf"):
return -1
return res
注意是,应该是:(不要用k哦)
for kk in range(1,n+1)
Bellman Ford算法:
该算法用于在带权图中(可以有负权边)找到从单一源点到所有其他顶点的最短路径,也可以检测是否有负权环。
检测负环的原理基于这样一个事实:在一个包含n
个顶点的图中,任何两个顶点之间的最短路径最多包含n-1
条边。因此,Bellman-Ford算法的基本步骤包括对所有边重复进行n-1
次松弛操作。松弛操作即:if(res[a]!=INT_MAX && res[a]+w<res[b]){ res[b]=res[a]+w; }
代码:
C++:
class Solution {
public:
int networkDelayTime(vector<vector<int>>& times, int n, int k) {
vector<int> res(n+1,INT_MAX);
res[k]=0;
int len=times.size();
/*n-1次松弛操作*/
for(int i=1;i<=n-1;i++){
for(int j=0;j<len;j++){
int a=times[j][0];
int b=times[j][1];
int w=times[j][2];
if(res[a]!=INT_MAX && res[a]+w<res[b]){
res[b]=res[a]+w;
}
}
}
int fin=0;
for(int i=1;i<=n;i++){
fin=max(fin,res[i]);
}
if(fin==INT_MAX){return -1;}
return fin;
}
};
Python:
class Solution:
def networkDelayTime(self, times: List[List[int]], n: int, k: int) -> int:
res=[0x3f3f3f3f]*(n+1)
res[k]=0
len_=len(times)
for i in range(1,n):
for j in range(len_):
a=times[j][0]
b=times[j][1]
w=times[j][2]
if res[a]!=0x3f3f3f3f and res[a]+w<res[b]:
res[b]=res[a]+w
fin=0
for i in range(1,n+1):
fin=max(fin,res[i])
if fin==0x3f3f3f3f:
return -1
return fin