# 3、最短路径算法 & Dijkstra & Floyd

# AcWing 849. Dijkstra求最短路 I

# AcWing 850. Dijkstra求最短路 II

# AcWing 854. Floyd求最短路

第一种:自己实现的,不断更换中转点的一个过程

//需要注意重复边,取较小的那个权值

import java.util.*;
import java.util.concurrent.LinkedTransferQueue;

//ACWing
public class Main {
    public static void main(String[] args) {
        Main main = new Main();
        main.Dijkstra();
    }

    int n, m;
    int[][] lines;
    int[] values;
    int used[];
    int EXCEED = 99999999;

    void Dijkstra() {
        Scanner scanner = new Scanner(System.in);
        n = scanner.nextInt();
        m = scanner.nextInt();
        lines = new int[n + 1][n + 1];
        values = new int[n + 1];
        used = new int[n + 1];
        Arrays.fill(values, EXCEED);
        for (int i = 0; i < lines.length; i++) {
            Arrays.fill(lines[i], EXCEED);
        }

        Arrays.fill(used, -1);
        values[1] = 0;
        used[1] = 0;
        while (m-- > 0) {
            int x = scanner.nextInt();
            int y = scanner.nextInt();
            int z = scanner.nextInt();
            if (lines[x][y] < z) {
                z = lines[x][y];
            }
            lines[x][y] = z;
            if (x == 1) values[y] = z;
        }
        while (true) {
            int middle = EXCEED;
            int mid_pos = -1;
            for (int i = 1; i <= n; i++) {
                if (used[i] == -1 && values[i] < middle) {
                    middle = values[i];
                    mid_pos = i;
                }
            }
            if (mid_pos == -1) break;
            used[mid_pos] = 1;
            for (int i = 1; i <= n; i++) {
                if (values[mid_pos] + lines[mid_pos][i] < values[i]) {
                    values[i] = values[mid_pos] + lines[mid_pos][i];
                }
            }
        }
        if (values[n] == EXCEED) System.out.println("-1");
        else System.out.println(values[n]);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62

# 迪杰斯特拉算法的堆优化

import java.util.*;
import java.util.concurrent.LinkedTransferQueue;

//ACWing
public class Main {
    public static void main(String[] args) {
        Main main = new Main();
        main.Dijkstra();
    }

    int n, m;
    int N=1000010;
    int[] dist;
    int[] used;
    int []h=new int[N];
    int []e=new int[N];
    int []ne=new int[N];
    int []w=new int[N];
    int idx=1;
    //构造小顶堆:
    PriorityQueue<VerC> small_heap=new PriorityQueue<>();
    //用的是优先队列
    int EXCEED = 99999999;
    class VerC implements Comparable{
        int id,dist;
        public VerC(int id, int dist) {
            this.id = id;
            this.dist = dist;
        }

        @Override
        public int compareTo(Object o) {
            VerC verC= (VerC) o;
            return dist-verC.dist;
        }
    }
    void insert(int a,int b,int c){
        e[idx]=b;
        w[idx]=c;
        ne[idx]=h[a];
        h[a]=idx++;
    }
    void Dijkstra() {
        Scanner scanner = new Scanner(System.in);
        n = scanner.nextInt();
        m = scanner.nextInt();
        dist = new int[n + 1];
        used = new int[n + 1];
        Arrays.fill(dist, EXCEED);
        Arrays.fill(used, -1);
        Arrays.fill(h, -1);
        dist[1] = 0;
        used[1] = 1;
        small_heap.offer(new VerC(1,0));
        while (m-- > 0) {
            int x = scanner.nextInt();
            int y = scanner.nextInt();
            int z = scanner.nextInt();
            insert(x,y,z);
        }
        while(!small_heap.isEmpty()){
            VerC verC=small_heap.poll();
            int mid_pos=verC.id;
            for(int i=h[mid_pos];i!=-1;i=ne[i]){
                int j=e[i];
                //j是头结点的下一个结点值
                //w[i]代表从头结点e[i]到j的距离
                if(dist[j]>dist[mid_pos]+w[i]&&used[j]==-1){
                    dist[j]=dist[mid_pos]+w[i];
                    small_heap.offer(new VerC(j,dist[j]));
                }
            }
            used[mid_pos]=1;
        }
        if(dist[n]== EXCEED) System.out.println(-1);
        else System.out.println(dist[n]);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78

# Floyd最短路径算法

import java.util.*;
import java.util.concurrent.LinkedTransferQueue;

//ACWing
public class Main {
    public static void main(String[] args) {
        Main main = new Main();
        main.Floyd();
    }

    int n, m;
    int[][] g;
    int[] values;
    int EXCEED = 10000010;
    int EXCEED_LINE = 100010;

    //一开始错的根本原因是
    //没有考虑重复边覆盖的特殊情况
    //每次给边定权值的时候应该考虑最小的那个情况
    void Floyd() {
        Scanner scanner = new Scanner(System.in);
        n = scanner.nextInt();
        m = scanner.nextInt();
        int kk = scanner.nextInt();
        g = new int[n + 1][n + 1];
        for (int i = 0; i <= n; i++) {
            Arrays.fill(g[i], EXCEED);
            g[i][i] = 0;
        }
        while (m-- > 0) {
            int a = scanner.nextInt();
            int b = scanner.nextInt();
            int z = scanner.nextInt();
            g[a][b] = Math.min(g[a][b],z);
        }
        //k是具体选用的哪个中转点
        for (int k = 1; k <= n; k++)
            for (int i = 1; i <= n; i++)
                for (int j = 1; j <= n; j++)
                    g[i][j] = Math.min(g[i][k] + g[k][j], g[i][j]);
        for (int i = 0; i < kk; i++) {
            int x = scanner.nextInt();
            int y = scanner.nextInt();
            if (g[x][y] >= EXCEED_LINE) {
                System.out.println("impossible");
            } else {
                System.out.println(g[x][y]);
            }
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51