How to store information has been mentioned in the previous section. I won't repeat it here. Let's briefly review the implementation content. Since the newcomers don't know how long the blog can be sent, they still need to ask the viewer Tp to go to the previous section: [Java implementation] simple implementation of Nanjing Metro navigation system (I) -- storing station information_ kksp993 blog - CSDN blog
catalogue
Multi segment graph weight vector table
Algorithm design under three requirements (I) -- fewer sites
Determination of weight vector table
Algorithm design under three requirements (II) -- replace with less
Determination of weight vector table
Algorithm design under three requirements (III) -- less time
Backtracking for Floyd algorithm
Backtracking for dynamic programming
Implementation content
Take the operation diagram of Nanjing Metro as the template to realize the planning and dynamic display effect of the optimal path navigation between any two stations. Specific template pictures and requirements are as follows:
1. Store the station information of Nanjing metro line.
2. Given the starting station and terminal station, assuming that the path lengths of adjacent stations are equal, find the subway ride scheme with the shortest path;
3. Given the starting station and terminal station, assuming that the path lengths of adjacent stations are equal, find the subway ride scheme with the least transfer times. If there are multiple ride schemes with the same transfer times, give the ride scheme with the least transfer times and the shortest path length.
4. In practical application, the distance between adjacent stations is not equal. Assuming that the subway stay time in transfer station is T1, the subway stay time in non transfer station is T2, the time consumption of subway transfer is T3 (regardless of the time waiting for subway), the average subway speed is v, and the path length of adjacent stations is known. Try: given the starting station and terminal station, Seek the subway ride scheme with the shortest ride time.
5. Design a visual query interface to dynamically display the above contents.
problem analysis
Obviously, these five steps are based on the difficulty from shallow to deep, and can be divided into the following layers:
(1) Minimum number of passing sites: the minimum number of passing sites can be realized by the number of passing sites from the beginning to the end
(2) Minimum transfer times: if it is changed to the minimum, it can be classified as a large penalty for the transfer at the above stations;
(3) Shortest theoretical time: it is necessary to calculate the waiting time, transfer time, operation time and many other factors respectively to correct the above process.
This topic is progressive layer by layer, which obviously needs to use the method of transformation. Next, we will analyze the methods used.
Selection of algorithm
The conventional algorithm selection is generally: dijestra algorithm and Freud algorithm.
Dijestra algorithm: [advantage] the complexity is lower than Floyd algorithm, which is O(e · logv).
[disadvantage] because each query needs to go through every link of the algorithm again, and the response time is long.
[related algorithm portal] Detailed principle, code implementation and complexity analysis of single source shortest path dijkstra algorithm_ Alan Zzx's blog - CSDN blog_ dijkstra algorithm complexity
Freudian algorithm: [advantages] the routing matrix and routing overhead can be obtained at one time and saved for use. It does not need to be corrected until the map is updated.
[disadvantage] the calculation time is too long:, and saving a large non sparse matrix undoubtedly increases the overhead.
[related algorithm portal] Shortest path template + parsing - (floyd algorithm)_ ytuyzh's blog - CSDN blog_ floyd algorithm
These two methods are excellent methods that have been used for a long time, and we need to learn from them. However, the so-called reference is definitely not copying. We need to understand the essence, understand its core and use it thoughtfully. "Everything starts from reality and seeks truth from facts" is right. Do other people's pictures look the same as ours? Is it best if we use it directly? Not necessarily. Therefore, we should make a detailed analysis according to the specific situation, and we can't copy and do it with the aid of bookishness. In this way, there will be no progress. Seeing the essence of the problem is the best shortcut to help us solve the problem. If we rashly set up a formula without seeing the essence of the problem, it will only be a spectrum resistant drug, not a targeted specific drug. Although there is an effect, it is certainly not as good as a specific drug. This is the trade-off between scope and effect. You can't have both fish and bear's paw. Since the topic is specific, why not use "special drugs"?
Without gossip, we can easily find that the subway route map has the following distinctive features:
(1) The subway is mainly composed of a few transfer stations, accounting for almost 10%
(2) Subway non transfer station can only travel in two directions, and it is only one-way for purposeful passengers. This means that the adjacency matrix is very sparse.
(3) Subway is very careful about whether each line transfers or not, so the calculation of the shortest path generally needs special treatment.
Therefore, we grasp the two characteristics of few transfer stations and no turning for non transfer, and we can think that the cost between non transfer can be regarded as a whole. In this way, there are less than 20 nodes that need to be concerned, and the rest are hidden in the weight information of the edge.
Considering the above process combined with the meaning of the topic, Freud will no longer have a headache - the number of transfer stations is rare, the complexity is greatly reduced, and the time is greatly saved. Therefore, the whole problem is simplified as follows:
(1) From the starting point to the transfer station
(2) Transfer station Floyd arriving at the transfer station
(3) From transfer station to terminal station
Special treatment is required for those who do not need to transfer or only transfer once, because it may not be necessary to refer to the results of Floyd algorithm.
Then we think, are these three steps very similar to the multi segment graph problem in the dynamic programming algorithm? Starting from the starting station is stage 0, the transfer station at the starting point is stage 1, the transfer station at the terminal is stage 2, and the terminal is stage 3. Since the step may be skipped if there is no transfer or less transfer, the unified process should not be omitted, but set the cost of the step to 0. The following figure shows the meaning of multi segment diagram and algorithm flow chart.
[related algorithm portal] Dynamic programming method to solve the shortest path problem of multi segment graph - Wuqi WhiteMoon - blog Park
Design of weight vector table
We need to provide two weight vector tables - Floyd weight vector table and multi segment graph weight vector table. Among the latterAnd
The weight vectors between need to refer to the results of the former Floyd algorithm.
Floyd weight vector table
Because the algorithm records the weight vector between transfer stations, the node only includes less than 20 transfer stations; Because the graph is undirected, the weight vector matrix is a symmetric matrix. You only need to fill in the weight vector table in one direction and copy it according to the main diagonal. If there are m transfer stations, the matrix should be a symmetric matrix of m*m.
Multi segment graph weight vector table
Consider the composition of the weight vector table of the multi segment graph: it is not difficult to find that the main nodes are,
,
,
. Let them form a row of vectors in order
The array length of is
,
The length of the is
, as shown in the figure below:
In this way, the weight vector table labeled by the above row vector should be row and column A square of. Since this is a single source path calculation, only the shortest route in one direction needs to be answered, and the main diagonal elements are 0, so only the upper triangular matrix (excluding the main diagonal) is concerned. If the record "-" indicates no concern (set as INFTY), * indicates that there are numbers and INF indicates unreachable, so the following matrix can be initialized:
Algorithm design under three requirements (I) -- fewer sites
Determination of weight vector table
yesThe path weight should be the number of sides the path passes through, and for
Unreachable binary pair
, its path weight should be set to infinity:
Algorithm design under three requirements (II) -- replace with less
Model modification
Obviously, less transfer is the first goal, and less passing is the second goal. Those who have participated in the college entrance examination may have this experience. When the total score is the same, give priority to the calculation of math scores, English scores and Chinese scores (each province may be different, but ours is not the same set. Don't care about these details). How does the system calculate at this time? Those who have seen the final admission score understand that it will display 348.124139085 (I wrote it casually, don't take a seat according to the number). It seems that it just writes the results side by side. Why is there a distinction of priority? The reason is that it weights the score - equivalent to multiplying it by a weight vector.
So, how to strengthen this goal and replace it with less in our model? As long as a penalty term (large coefficient) is set at the real transfer station, the results under the strengthened target will be given priority in the calculation process, and the influence of the non strengthened target will be limited. Specifically, Ts is set as the transfer station, Represents the edge on the OT path, and the objective function can be expressed as follows:
among λ You should select a value that is much larger than the length of a single line. Select here λ= 100, of course, the bigger the better.
(I conservatively chose 10 and then overturned...)
Determination of weight vector table
For the weight vector table, the penalty coefficient needs to be added in the following two aspects:
(1) Floyd weight vector table: during initialization, each "*" needs to be added and replaced with a loss λ.
(2) Multi segment graph weight vector table: for the first arrival at the transfer station and from the transfer station to the terminal station, it is necessary to increase and replace it with loss λ, Since the number of lines should be more than once, it can be considered to record onlyExchange loss λ. (if both are considered, it will be inconsistent with the actual situation, but it will have no impact on the program running results)
Algorithm design under three requirements (III) -- less time
Model modification
In practical application, the distance between adjacent stations is not equal. Many factors need to be considered, such as transit station subway dwell time, non transit station subway dwell time, subway running speed, subway running distance between each station and so on. According to the simplified model required by the topic, we set the transit station subway stay time as T1, the non transit station subway stay time as T2, the subway transfer time consumption as T3 (regardless of the waiting time for the subway), the average subway speed as v, and the path length of adjacent stations as d. Therefore, we need to recalculate the weight matrix under the new constraint.
By consulting the data, we can get the information table of the distance between Nanjing Metro Stations: Distance between stations of Nanjing Metro Line S7 - Nanjing local treasure
Site index | 1 / Mai Yao | 2 / oil via | 3 / forest forage | 4 / Dragon Fairy | 10 / rain an | s1 / Lu Nan | s3 / Huang Nan | s7 / none - Lu | s8 / Thai Kim | s9 / Xiang Gao |
1 | 1142 | 2631 | 2537 | 1574 | 1729 | 7926 | 1712 | 1229 | 1236 | 10003 |
2 | 1121 | 1622 | 1049 | 1828 | 1154 | 4234 | 1998 | 2261 | 2741 | 7374 |
3 | 1691 | 1262 | 1127 | 821 | 1427 | 7283 | 1350 | 1529 | 2830 | 11219 |
4 | 1061 | 1379 | 1407 | 1359 | 1134 | 4723 | 1471 | 2423 | 1401 | 16912 |
5 | 1254 | 1473 | 1854 | 807 | 833 | 3242 | 1324 | 5236 | 1829 | 6232 |
6 | 862 | 1312 | 3535 | 1391 | 4545 | 3252 | 2099 | 3138 | 2151 | 0 |
7 | 1147 | 1257 | 961 | 2018 | 1350 | 4077 | 9844 | 5502 | 3880 | 0 |
8 | 1125 | 1002 | 1845 | 1128 | 1512 | 0 | 1525 | 5486 | 1567 | 0 |
9 | 909 | 874 | 1379 | 2749 | 848 | 0 | 2007 | 962 | 2893 | 0 |
10 | 1914 | 745 | 2017 | 2569 | 1865 | 0 | 1037 | 0 | 2077 | 0 |
11 | 2093 | 1022 | 2851 | 2564 | 1400 | 0 | 949 | 0 | 2375 | 0 |
12 | 1455 | 1024 | 858 | 3233 | 1307 | 0 | 1154 | 0 | 1606 | 0 |
13 | 1283 | 1300 | 859 | 1187 | 2157 | 0 | 1187 | 0 | 1475 | 0 |
14 | 1076 | 1521 | 931 | 1938 | 0 | 0 | 1608 | 0 | 6112 | 0 |
15 | 1853 | 1307 | 1067 | 2454 | 0 | 0 | 1446 | 0 | 4971 | 0 |
16 | 2276 | 937 | 1308 | 2185 | 0 | 0 | 1507 | 0 | 5475 | 0 |
17 | 1345 | 1168 | 1143 | 3212 | 0 | 0 | 1470 | 0 | 0 | 0 |
18 | 904 | 2779 | 977 | 0 | 0 | 0 | 1963 | 0 | 0 | 0 |
19 | 1332 | 3015 | 1153 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
20 | 1475 | 1675 | 1137 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
21 | 1135 | 1326 | 1222 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
22 | 1919 | 1519 | 1105 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
23 | 1312 | 1066 | 1826 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
24 | 1550 | 1947 | 1791 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
25 | 2720 | 1846 | 2343 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
26 | 1964 | 0 | 1526 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
27 | 0 | 0 | 1301 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
28 | 0 | 0 | 2995 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
Since the current goal is to minimize the time consumption, the weights in the weight table should store the time consumption between two points. The time consumption of taking the subway can be divided into the following parts:
I. Metro operation duration:
2. Subway stops and waits often:
3. Additional consumption of metro transfer station:
4. Additional consumption of transfer in Subway:
In order to have the same function form as the first two questions and obtain a unified formula applicable to three types of problems for easy calling, the four functions are defined and unified as follows:
Backtracking of path
Backtracking for Floyd algorithm
Generally, there are two modes for Floyd's routing matrix records on the Internet and in textbooks (more common...). One is the online version, which is forNot as good as
The grid update route array records K, and the other is written in algorithm design analysis and design (Chen Huinan). The recorded value here is path[k][j], that is, the last step before reaching j after passing through K. Let's compare the advantages and disadvantages of these two methods for this problem:
(1) Record k: this path backtracking needs to be traversed in middle order in the form of binary tree. It may be difficult for those with poor knowledge of binary tree, and they need to constantly if...else.
(2) Record the last routing path: this record form is linear, which is convenient to obtain the shortest path.
Therefore, we choose the second way of recording, linear backtracking.
/** * Find the transit path of S2 - > S3 * * @return S2->S3 All transit paths, including arraylist at the beginning and end stations */ private static ArrayList<Station> FloydTraceBack(Station s1, Station s2) { // if (s1.equals(s2)) System.err.println("FloydTraceBack-found:" + s1 + "==" + s2); ArrayList<Station> floydPath = new ArrayList<>(); int idx1 = getStationIdx(TS_station, s1); Station temp = s2; do { floydPath.add(temp); } while (!s1.equals(temp = TS_path[idx1][getStationIdx(TS_station, temp)])); floydPath.add(s1); Collections.reverse(floydPath); return floydPath; }
Backtracking for dynamic programming
Because the backtracking in the first and third stages is the backtracking on the line, which is very simple; The intermediate backtracking has been completed in the above steps. Therefore, only these steps need to be connected in series. The details are as follows:
/** * Find and add stations in turn to complete route planning * dp_path:[S0,S1,S2,S3] * TS-path:[all TS station]*[all TS station] * linear_path:Obtain the path array on the same line through the Station method * * @return path: Store all routing stations in S0, S1, S2 and S3 in turn */ private static ArrayList<Station> trace4Path() { path.clear(); //Record each station from back to front //S3 Station s3 = dp_tags[dp_tags.length - 1]; path.add(s3); //S3<-S2 Station s2 = dp_path[dp_tags.length - 1]; addList2Path(s3, s2); //S2 < - S1: obtain the route map of S1 - > S2, reverse the order and delete S2, and record the routing stations in turn Station s1 = dp_path[getStationLastIdx(dp_tags, s2)]; if (s1.equals(s2)) s1=dp_path[getStationIdx(dp_tags,s2)]; //If only transfer is required, S1==S2 should skip S1 and directly S2 < - S0 if (s1.isTS()) { ArrayList<Station> tbArrays = FloydTraceBack(s1, s2); Collections.reverse(tbArrays); tbArrays.remove(0); Station pre = s2; for (Station cur : tbArrays) { addList2Path(pre, cur); pre = cur; } //S1<-S0 Station s0 = dp_path[0]; addList2Path(s1, s0); } else { Station s0 = dp_path[0]; addList2Path(s2, s0); } //Use Collections.reverse(path); In reverse order Collections.reverse(path); Utils.print1D(path.toArray(), 5, "path"); return path; }
To sum up, the overall process is as follows:
/** * Calculate and return the shortest distance between two stations * * @param S0 Starting station * @param S3 Terminus * @return distance */ public static double PathNavigation(Station S0, Station S3, double TS_Non) { double d = A, d1 = A; double[][] Dp_w; System.out.println("------------start--------------" + TS_Non); //generate all station information if (!initStationInfo(S0, S3)) d1 = getLinearDistance(S0, S3, TS_Non) - (TS_STAY_MIN - NON_STAY_MIN) * (TS_Non - 1); //generate all transferring stations' weight matrix TS_cost = initTS_W_Matrix(TS_Non); floyd(); //generate dp's weight matrix Dp_w = initDp_W_Matrix(S0, S1, S2, S3, TS_Non); d = dp(Dp_w); //compare and the least cost between two methods if (d < d1) trace4Path(); else System.out.println("Direct best:" + d1); System.out.println("-------------end---------------"); return d; }
All codes in this file are listed below:
package core; import utils.Utils; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; /** * @author kksp993 */ public class PathHelper { public static final int A = 2097152; public static final double TS_COST = 5; public static final double TS_STAY_MIN = 3; public static final double NON_STAY_MIN = 1; public static final double V_KM_H = 60; private static Station[] S1; private static Station[] S2; private static Station[] TS_station; private static double[][] TS_cost; private static Station[][] TS_path; private static Station[] dp_tags; private static double[] dp_cost; private static Station[] dp_path; private static ArrayList<Station> path; /** * Calculate and return the shortest distance between two stations * * @param S0 Starting station * @param S3 Terminus * @return distance */ public static double PathNavigation(Station S0, Station S3, double TS_Non) { double d = A, d1 = A; double[][] Dp_w; System.out.println("------------start--------------" + TS_Non); //generate all station information if (!initStationInfo(S0, S3)) d1 = getLinearDistance(S0, S3, TS_Non) - (TS_STAY_MIN - NON_STAY_MIN) * (TS_Non - 1); //generate all transferring stations' weight matrix TS_cost = initTS_W_Matrix(TS_Non); floyd(); //generate dp's weight matrix Dp_w = initDp_W_Matrix(S0, S1, S2, S3, TS_Non); d = dp(Dp_w); //compare and the least cost between two methods if (d < d1) trace4Path(); else System.out.println("Direct best:" + d1); System.out.println("-------------end---------------"); return d; } /** * Initialize S0~S3 site information * * @param S0 Starting station * @param S3 Terminus * @return If directly connected, false, otherwise true */ private static boolean initStationInfo(Station S0, Station S3) { path = new ArrayList<>(); S1 = Utils.list2Array(S0.getLinearTs()); S2 = Utils.list2Array(S3.getLinearTs()); TS_station = Utils.list2Array(Station.getAllTS()); if (S0.commonLineNum(S3) < A) { path.add(S0); addList2Path(S0, S3); return false; } return true; } /** * Obtain the shortest path by multi segment graph method: * 1)S0->S1:Process of non transfer station arriving at transfer station * ->stition Class to obtain the distance / station name of all transfer stations on your line * 2)S1->S2:The process of the transfer station arriving at the terminal transfer station * ->Floyd Get parameter table * 3)S2->S3:The process of CLP transit station reaching the key points * ->stition Class to obtain the distance / station name of all transfer stations on your line * The above parameters need to be passed in w * * @param w Record the matrix of all key nodes * @return Weight of the least path */ public static double dp(double[][] w) { dp_cost = new double[w.length]; dp_path = new Station[w.length]; Arrays.fill(dp_cost, Integer.MAX_VALUE); dp_path[0] = dp_tags[0]; dp_cost[0] = 0; for (int j = 1; j < w.length; j++) for (int i = j - 1; i >= 0; i--) if (w[i][j] != A) { double d = dp_cost[i] + w[i][j]; if (d < dp_cost[j]) { dp_cost[j] = d; dp_path[j] = dp_tags[i]; } } Utils.print1D(dp_tags, 5, "dp_tags"); Utils.print1D(dp_path, 5, "dp_path"); Utils.print1D(dp_cost, 8, "dp_cost"); return dp_cost[w.length - 1]; } /** * floyd To calculate the weight variables between all transfer stations, TS needs to be prepared in advance_ cost */ public static void floyd() { TS_path = new Station[TS_station.length][TS_station.length]; //Initialize routing matrix for (int i = 0; i < TS_station.length; i++) for (int j = 0; j < TS_station.length; j++) TS_path[i][j] = TS_cost[i][j] < A ? TS_station[i] : null; //Traversal floyd for (int i = 0; i < TS_station.length; i++) for (int j = 0; j < TS_station.length; j++) for (int k = 0; k < TS_station.length; k++) if (TS_cost[i][k] + TS_cost[k][j] < TS_cost[i][j]) { TS_cost[i][j] = TS_cost[i][k] + TS_cost[k][j]; TS_path[i][j] = TS_path[k][j]; } } /** * Initialize the transfer station weight table for floyd algorithm * * @param TS_Non: The weight of transfer station and non transfer station is 10 by default. The weight of passing stations is 1 by default * @return */ private static double[][] initTS_W_Matrix(double TS_Non) { double[][] w = new double[TS_station.length][TS_station.length]; for (int i = 0; i < TS_station.length; i++) { Arrays.fill(w[i], A); for (int j = 0; j < TS_station.length; j++) { if (i == j) w[i][j] = 0; else w[i][j] = getLinearDistance(TS_station[i], TS_station[j], TS_Non); } } return w; } /** * 1:Minimum station / 2: maximum speed / 100: minimum transfer * * @param s1 Starting station * @param s2 Terminus * @param TS_Non Transfer weight ratio = transfer station weight / non transfer station weight * 1:Minimum station / 2: maximum speed / 100: minimum transfer * @return S1 Linear shortest overhead to S2 */ private static double getLinearDistance(Station s1, Station s2, double TS_Non) { double speed = TS_Non == 2 ? V_KM_H / 60 * 1000 : 1; int isPd = TS_Non == 2 ? 1 : 0; //Generally, the station stops frequently double stayTime = Math.abs(s1.linearDistance(s2, false)) * NON_STAY_MIN; //Extra cost of transfer double TsExtraCost = (TS_STAY_MIN - NON_STAY_MIN) * (TS_Non - 1); //Subway operation often double runningTime = isPd * Math.abs(s1.linearDistance(s2, true)) / speed; //Extra cost of routing transfer station double TsPassCost = isPd * s1.getInnerTsNum(s2) * (TS_COST - TS_STAY_MIN); return stayTime + TsExtraCost + runningTime + TsPassCost; } /** * Initialize weight table and header information * * @param S0 starting point * @param S1 Starting point transfer station * @param S2 Terminal transfer station * @param S3 End * @param TS_Non: The weight of transfer station and non transfer station is 10 by default. The weight of passing stations is 1 by default * @return Weight table */ private static double[][] initDp_W_Matrix(Station S0, Station[] S1, Station[] S2, Station S3, double TS_Non) { double[][] w = new double[S1.length + S2.length + 2][S1.length + S2.length + 2]; dp_tags = new Station[S1.length + S2.length + 2]; //Initialize dp_tags is used to store header information: dp_tags[0] = S0; for (int i = 0; i < S1.length; i++) dp_tags[1 + i] = S1[i]; for (int i = 0; i < S2.length; i++) dp_tags[1 + S1.length + i] = S2[i]; dp_tags[dp_tags.length - 1] = S3; //w is initialized to infinity, indicating unreachable for (double[] w_row : w) Arrays.fill(w_row, A); //w diagonal all 0 for (int i = 0; i < w.length; i++) w[i][i] = 0; //Process the weight table of S0 - > S1 //The transfer ratio only calculates the starting point, not the ending point. TS has finished generating the Matrix for (int i = 0; i < S1.length; i++) { w[0][1 + i] = getLinearDistance(S0, S1[i], TS_Non); } //Process S1 - > S2 weight table for (int i = 0; i < S1.length; i++) { for (int j = 0; j < S2.length; j++) { int idx1 = getStationIdx(TS_station, S1[i]); int idx2 = getStationIdx(TS_station, S2[j]); //Only the upper triangle of w is processed w[1 + i][1 + S1.length + j] = TS_cost[idx1][idx2]; } } //Process the weight table of S2 - > S3 for (int i = 0; i < S2.length; i++) { //Remove the transfer ratio of multiple records at the tail end w[1 + S1.length + i][w.length - 1] = getLinearDistance(S3, S2[i], TS_Non) - (TS_Non - 1) * (TS_STAY_MIN - NON_STAY_MIN); } return w; } /** * Gets the coordinates of the station in the array * * @param stations Search scope * @param key Looking for elements * @return index value found */ private static int getStationIdx(Station[] stations, Station key) { for (int i = 0; i < stations.length; i++) if (key.equals(stations[i])) return i; return -1; } /** * Get the coordinates of the station in the array from back to front * * @param stations Search scope * @param key Looking for elements * @return index value found */ private static int getStationLastIdx(Station[] stations, Station key) { for (int i = stations.length - 1; i >= 0; i--) if (key.equals(stations[i])) return i; return -1; } /** * Find and add stations in turn to complete route planning * dp_path:[S0,S1,S2,S3] * TS-path:[all TS station]*[all TS station] * linear_path:Obtain the path array on the same line through the Station method * * @return path: Store all routing stations in S0, S1, S2 and S3 in turn */ private static ArrayList<Station> trace4Path() { path.clear(); //Record each station from back to front //S3 Station s3 = dp_tags[dp_tags.length - 1]; path.add(s3); //S3<-S2 Station s2 = dp_path[dp_tags.length - 1]; addList2Path(s3, s2); //S2 < - S1: obtain the route map of S1 - > S2, reverse the order and delete S2, and record the routing stations in turn Station s1 = dp_path[getStationLastIdx(dp_tags, s2)]; if (s1.equals(s2)) s1=dp_path[getStationIdx(dp_tags,s2)]; //If only transfer is required, S1==S2 should skip S1 and directly S2 < - S0 if (s1.isTS()) { ArrayList<Station> tbArrays = FloydTraceBack(s1, s2); Collections.reverse(tbArrays); tbArrays.remove(0); Station pre = s2; for (Station cur : tbArrays) { addList2Path(pre, cur); pre = cur; } //S1<-S0 Station s0 = dp_path[0]; addList2Path(s1, s0); } else { Station s0 = dp_path[0]; addList2Path(s2, s0); } //Use Collections.reverse(path); In reverse order Collections.reverse(path); Utils.print1D(path.toArray(), 5, "path"); return path; } /** * Add linear routing stations in turn to the arrival path, excluding the starting station * * @param sta Starting point site * @param end Terminal station * @return Current path */ private static ArrayList<Station> addList2Path(Station sta, Station end) { Station[] stations = sta.linearPathTo(end); // if (stations==null) return path; for (int i = 1; i < stations.length; i++) path.add(stations[i]); return path; } /** * Find the transit path of S2 - > S3 * * @return S2->S3 All transit paths, including arraylist at the beginning and end stations */ private static ArrayList<Station> FloydTraceBack(Station s1, Station s2) { // if (s1.equals(s2)) System.err.println("FloydTraceBack-found:" + s1 + "==" + s2); ArrayList<Station> floydPath = new ArrayList<>(); int idx1 = getStationIdx(TS_station, s1); Station temp = s2; do { floydPath.add(temp); } while (!s1.equals(temp = TS_path[idx1][getStationIdx(TS_station, temp)])); floydPath.add(s1); Collections.reverse(floydPath); return floydPath; } public static ArrayList<Station> getPath() { return path; } }
Well, the above is how to implement the shortest path algorithm to complete the data reading of three requirements. Thank you for three times with one click. In the next section, we will continue to talk about the production of simple GUI Graphical interface.