Post

PTA旅游规划(JAVA)

JAVA中优化了输入通过的一道题

题目大意

有了一张自驾旅游路线图,你会知道城市间的高速公路长度、以及该公路要收取的过路费。现在需要你写一个程序,帮助前来咨询的游客找一条出发地和目的地之间的最短路径。如果有若干条路径都是最短的,那么需要输出最便宜的一条路径。

输入格式:

输入说明:输入数据的第 1 行给出 4 个正整数 nmsd,其中 n2n500)是城市的个数,顺便假设城市的编号为 0~(n1);m 是高速公路的条数;s 是出发地的城市编号;d 是目的地的城市编号。随后的 m 行中,每行给出一条高速公路的信息,分别是:城市 1、城市 2、高速公路长度、收费额,中间用空格分开,数字均为整数且不超过 500。输入保证解的存在。

输出格式:

在一行里输出路径的长度和收费总额,数字间以空格分隔,输出结尾不能有多余空格。

输入样例:

4 5 0 3
0 1 1 20
1 3 2 30
0 3 4 10
0 2 2 20
2 3 1 20

输出样例:

3 40

java代码解决

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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;

import static java.lang.Math.max;
import static java.lang.Math.min;

public class Main {
    static int[][] g = new int[509][509];
    static int[][] expense = new int[509][509];
    static int[] dist = new int[509];
    static int[] cost = new int[509];
    static PriorityQueue<pair> pq = new PriorityQueue<>();
    static int n,m,s,d;
    static boolean[] vis = new boolean[509];

    public static class pair implements Comparable<pair> {
        int x, y;
        public pair(int x, int y) {
            this.x = x;
            this.y = y;
        }

        @Override
        public int compareTo(pair o) {
            return this.y - o.y;
        }
    }

    public static void dijkstra() {
        for(int i=0;i<n;i++) {
            dist[i] = Integer.MAX_VALUE;
        }
        for(int i=0;i<n;i++) {
            cost[i] = Integer.MAX_VALUE;
        }
        dist[s] = 0;
        cost[s] = 0;
        pq.add(new pair(s,dist[s]));
        while(!pq.isEmpty()) {
            pair p = pq.poll();

            if(vis[p.x]) continue;
            vis[p.x] = true;

            for(int i=0;i<n;i++) {
                if(vis[i]) continue;
                if(g[p.x][i] != -1 && dist[i] > dist[p.x] + g[p.x][i]) {
                    dist[i] = dist[p.x] + g[p.x][i];
                    cost[i] = cost[p.x] + expense[p.x][i];
                    pq.add(new pair(i,dist[i]));
                }
                if(g[p.x][i] != -1 && dist[i] == dist[p.x] + g[p.x][i]) {
                    cost[i] = min(cost[p.x] + expense[p.x][i],cost[i]);
                }
            }
        }
    }

    static class FastReader {
        BufferedReader br;
        StringTokenizer st;

        public FastReader() {
            br = new BufferedReader(new InputStreamReader(System.in));
        }

        String next() {
            while (st == null || !st.hasMoreElements()) {
                try {
                    st = new StringTokenizer(br.readLine());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return st.nextToken();
        }

        int nextInt() {
            return Integer.parseInt(next());
        }
    }

    public static void main(String[] args) {
        FastReader scanner = new FastReader();
        n = scanner.nextInt();
        m = scanner.nextInt();
        s = scanner.nextInt();
        d = scanner.nextInt();
        for(int i=0;i<509;i++) {
            for(int j=0;j<509;j++) {
                g[i][j] = -1;
                expense[i][j] = -1;
            }
        }
        for(int i=0;i<m;i++) {
            int u = scanner.nextInt();
            int w = scanner.nextInt();
            int dis = scanner.nextInt();
            int e = scanner.nextInt();
            g[u][w] = dis;
            g[w][u] = dis;
            expense[u][w] = e;
            expense[w][u] = e;
        }
        dijkstra();
        System.out.print(dist[d] + " ");
        System.out.print(cost[d]);
    }
}

大致思路

本题涉及双权值最短路问题,用了优先队列优化,但是由于用的是邻接矩阵,所以如果n再大些可能就无法通过,最好改成邻接表。

在此题中,有可能多个路径长度一样,要选择收费最低的,这就是多权值的体现,为了解决这个问题,我们会在路径长度需要更新的时候修改最小花费,注意是修改不是更新,因为遇到路径更短的情况时不论前一个收费多低或者多高,都是不可取的,核心代码如下

1
2
3
4
5
6
7
8
if(g[p.x][i] != -1 && dist[i] > dist[p.x] + g[p.x][i]) {
                dist[i] = dist[p.x] + g[p.x][i];
                cost[i] = cost[p.x] + expense[p.x][i];
                pq.add(new pair(i,dist[i]));
            }
            if(g[p.x][i] != -1 && dist[i] == dist[p.x] + g[p.x][i]) {
                cost[i] = min(cost[p.x] + expense[p.x][i],cost[i]);
            }

那么如果是cpp代码本题就到此为止了,但是关键在于java代码输入很慢,也因此卡了我一段时间

输入优化

我们在Main类中定义快速输入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
static class FastReader {
        BufferedReader br;
        StringTokenizer st;

        public FastReader() {
            br = new BufferedReader(new InputStreamReader(System.in));
        }

        String next() {
            while (st == null || !st.hasMoreElements()) {
                try {
                    st = new StringTokenizer(br.readLine());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return st.nextToken();
        }

        int nextInt() {
            return Integer.parseInt(next());
        }
    }

并且将Scanner换成FasterReader即可

至此,本题在完全图的情况下也能控制在800ms以内,完结撒花🎉🎉🎉

This post is licensed under CC BY 4.0 by the author.