leetcode 743题
一、存图方式
1、邻接矩阵
int[][] w = new int[N][N];
void add(int a, int b, int c){
w[a][b] = c;
}
2、邻接表(链式前向星存图)
int[] head = new int[N]; //存储某个结点所对应边集合(链表)中最后一条边的头结点在数组中的位置
int[] edge = new int[M]; //某条边指向的另一个结点
int[] next = new int[M]; //以链表的形式存储边,存储同起点的边集合
int[] w = new int[M]; //边的权重
int index; //边的索引
void add(int a, int b, int c){
edge[index] = b;
next[index] = head[a];
head[a] = index; //头插法
w[index] = c;
index++;
}
//遍历同起点的边
for(int i = head[a]; i != -1; i = next[i]){
int b = edge[i];
int c = w[i];
}
3、类存图
二、Floyd算法
1、邻接矩阵
class Solution{
int N = 110, M = 6010;
int[][] w = new int[N][M];
int INF = 0x3f3f3f3f;
int n, k;
public int networkDelayTime(int[][] ts, int _, int _k){
n = _n;
k = _k;
//初始化邻接矩阵
for(int i = 1; i <= n; i++){
for(int j = 1;j <= n; j++){
w[i][j] = w[j][i] = i == j ? 0 : INF;
}
}
//存图
for(int[] t : ts){
w[t[0]][t[1]] = t[2];
}
//最短路径
floyd();
//遍历答案
int ans = 0;
for(int i = 1; i <= n; i++){
ans = Math.max(ans,w[k][i]);
}
return ans >= INF / 2; -1 : ans;
}
public void floyd(){
//floyd 算法模板
//考虑加入某个中转点之后路径的权重
for(int p = 1; p <= n; p++){
for(int i = 1; i<= n; i++){
for(int j = 1; j <= n; j++){
w[i][j] = Math.min(w[i][j],w[i][p] + w[p][j]);
}
}
}
}
}
三、朴素Dijksta
1、邻接矩阵
class Solution {
int N = 110, M = 6010;
// 邻接矩阵数组:w[a][b] = c 代表从 a 到 b 有权重为 c 的边
int[][] w = new int[N][N];
// dist[x] = y 代表从「源点/起点」到 x 的最短距离为 y
int[] dist = new int[N];
// 记录哪些点已经被更新过
boolean[] vis = new boolean[N];
int INF = 0x3f3f3f3f;
int n, k;
public int networkDelayTime(int[][] ts, int _n, int _k) {
n = _n; k = _k;
// 初始化邻接矩阵
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
w[i][j] = w[j][i] = i == j ? 0 : INF;
}
}
// 存图
for (int[] t : ts) {
int u = t[0], v = t[1], c = t[2];
w[u][v] = c;
}
// 最短路
dijkstra();
// 遍历答案
int ans = 0;
for (int i = 1; i <= n; i++) {
ans = Math.max(ans, dist[i]);
}
return ans > INF / 2 ? -1 : ans;
}
public void dijkstra(){
//先将所有的点标记为 未更新 和 距离为正无穷
Arrays.fill(vis,false);
Arrays.fill(dist,INF);
//起点距离为0
dist[k] = 0;
//迭代n次
for(int p = 1; p <= n; p++){
int t = -1;
//找到最小距离的点
for(int i = 1; i <= n; i++){
if(!vis[i] && (t == -1 || dist[i] < dist[t])) t = i;
}
//标记t 为已更新
vis[t] = true;
//用t的最小距离更新其他点
for(int i = 1; i <= n; i++){
dist[i] = Math.min(dist[i],dist[t] + w[t][i]);
}
}
}
}
四、堆优化Dijkstra
class Solution {
int N = 110, M = 6010;
// 邻接表
int[] he = new int[N], e = new int[M], ne = new int[M], w = new int[M];
// dist[x] = y 代表从「源点/起点」到 x 的最短距离为 y
int[] dist = new int[N];
// 记录哪些点已经被更新过
boolean[] vis = new boolean[N];
int n, k, idx;
int INF = 0x3f3f3f3f;
void add(int a, int b, int c) {
e[idx] = b;
ne[idx] = he[a];
he[a] = idx;
w[idx] = c;
idx++;
}
public int networkDelayTime(int[][] ts, int _n, int _k) {
n = _n; k = _k;
// 初始化链表头
Arrays.fill(he, -1);
// 存图
for (int[] t : ts) {
int u = t[0], v = t[1], c = t[2];
add(u, v, c);
}
// 最短路
dijkstra();
// 遍历答案
int ans = 0;
for (int i = 1; i <= n; i++) {
ans = Math.max(ans, dist[i]);
}
return ans > INF / 2 ? -1 : ans;
}
void dijkstra() {
// 起始先将所有的点标记为「未更新」和「距离为正无穷」
Arrays.fill(vis, false);
Arrays.fill(dist, INF);
// 只有起点最短距离为 0
dist[k] = 0;
// 使用「优先队列」存储所有可用于更新的点
// 以 (点编号, 到起点的距离) 进行存储,优先弹出「最短距离」较小的点
PriorityQueue<int[]> q = new PriorityQueue<>((a,b)->a[1]-b[1]);
q.add(new int[]{k, 0});
while (!q.isEmpty()) {
// 每次从「优先队列」中弹出
int[] poll = q.poll();
int id = poll[0], step = poll[1];
// 如果弹出的点被标记「已更新」,则跳过
if (vis[id]) continue;
// 标记该点「已更新」,并使用该点更新其他点的「最短距离」
vis[id] = true;
for (int i = he[id]; i != -1; i = ne[i]) {
int j = e[i];
if (dist[j] > dist[id] + w[i]) {
dist[j] = dist[id] + w[i];
q.add(new int[]{j, dist[j]});
}
}
}
}
}