Floyd是先固定中间节点,然后遍历所有其入度和出度的点。 Dijkstra是先固定源节点,然后遍历所有可能的中间节点和目的节点。
邻接矩阵(稠密图)还是邻接表(稀疏图)
Floyd
class Solution:
def findTheCity(self, n: int, edges: List[List[int]], distanceThreshold: int) -> int:
# Floyd 算法
# 求 每个 结点 到 其它结点的最短路。 然后查看 满足 距离在 distanceThreshold 内的数
res = (inf, -1) # 符合条件的邻居节点数 编号
e = [[inf] * n for _ in range(n)] # 任意两点间的最短路径
for u, v, w in edges:
e[u][v] = w
e[v][u] = w
for node in range(n): # O(n^3)
e[node][node] = 0
for u in range(n):
for v in range(n):
e[u][v] = min(e[u][v], e[u][node] + e[node][v]) # 邻接矩阵
for u in range(n):
cnt = sum(e[u][v] <= distanceThreshold for v in range(n))
if cnt <= res[0]: # 相等时 返回的是 编号更大的
res = (cnt, u)
return res[1]
class Solution {
public:
int findTheCity(int n, vector<vector<int>>& edges, int distanceThreshold) {
pair<int,int> res(INT_MAX / 2, -1);
vector<vector<int>> e(n, vector<int>(n, INT_MAX / 2));
for (auto eg : edges){//
int u = eg[0], v = eg[1], w = eg[2];
e[u][v] = w;
e[v][u] = w;
}
for (int k = 0; k < n; ++k){// 固定 中间结点
e[k][k] = 0;
for (int i = 0; i < n; ++i){// 入度节点
for (int j = 0; j < n; ++j){// 出度节点
e[i][j] = min(e[i][j], e[i][k] + e[k][j]); // 这里 相加了, 所以最大值只能是 INT_MAX / 2, 不然会溢出
}
}
}
for (int i = 0; i < n; ++i){
int cnt = 0;
for (int j = 0; j < n; ++j){
if (e[i][j] <= distanceThreshold){
cnt++;
}
}
if (cnt <= res.first){
res = {cnt, i};
}
}
return res.second;
}
};
Dijkstra
class Solution:
def findTheCity(self, n: int, edges: List[List[int]], distanceThreshold: int) -> int:
# Dijkstra 算法
# 求 每个 结点 到 其它结点的最短路。 然后查看 满足 距离在 distanceThreshold 内的数
res = (inf, -1) # 最短路径 编号
e = [[inf] * n for _ in range(n)]
dis = [[inf] * n for _ in range(n)] ##
visited = [[False] * n for _ in range(n)]
for u, v, w in edges:
e[u][v] = w
e[v][u] = w
##
for i in range(n): # 源节点 i
dis[i][i] = 0
for _ in range(n): #
t = -1 # t
# 找 最短的。 # 总代价 最低的扩展 分支定界思想
for k in range(n): #
if not visited[i][k] and (t == -1 or dis[i][k] < dis[i][t]): # t = -1 表示 刚进入该循环,
t = k # 未 遍历的点中, t 离 i 最近。
visited[i][t] = True # i 和 t 之间 最短路径已确定
for k in range(n): # 经过 i 和 t, 到达 k 的路径长度
dis[i][k] = min(dis[i][k], dis[i][t] + e[t][k])
for u in range(n):
cnt = sum(dis[u][v] <= distanceThreshold for v in range(n)) #
if cnt <= res[0]: # 相等时 返回的是 编号更大的
res = (cnt, u)
return res[1]
class Solution {
public:
int findTheCity(int n, vector<vector<int>>& edges, int distanceThreshold) {
pair<int,int> res(INT_MAX / 2, -1);
vector<vector<int>> e(n, vector<int>(n, INT_MAX / 2));
vector<vector<int>> dis(n, vector<int>(n, INT_MAX / 2));
vector<vector<int>> vis(n, vector<int>(n, false));
for (auto eg : edges){//
int u = eg[0], v = eg[1], w = eg[2];
e[u][v] = w;
e[v][u] = w;
}
for (int i = 0; i < n; ++i){
dis[i][i] = 0; // 源节点
for (int j = 0; j < n; ++j){// j 没 用。 只是
int t = -1;
for (int k = 0; k < n; ++k){
if (!vis[i][k] && (t == -1 || dis[i][k] < dis[i][t])){
t = k; // 未遍历节点 中 离 i 更近的结点 t
}
}
vis[i][t] = true; // 标记 已计算
// 更新 别的结点
for (int k = 0; k < n; ++k){// 经过 i 和 t 节点的路径 终点为 k 。 后续 有更短的,就更新
dis[i][k] = min(dis[i][k], dis[i][t] + e[t][k]); // 注意 这里 加 的是 e[t][k]
}
}
}
for (int i = 0; i < n; ++i){
int cnt = 0;
for (int j = 0; j < n; ++j){
if (dis[i][j] <= distanceThreshold){
cnt++;
}
}
if (cnt <= res.first){
res = {cnt, i};
}
}
return res.second;
}
};