一、题目
有了一张自驾旅游路线图,你会知道城市间的高速公路长度、以及该公路要收取的过路费。现在需要你写一个程序,帮助前来咨询的游客找一条出发地和目的地之间的最短路径。如果有若干条路径都是最短的,那么需要输出最便宜的一条路径。
输入格式:
输入说明:输入数据的第1行给出4个正整数N、M、S、D,其中N(2≤N≤500)是城市的个数,顺便假设城市的编号为0~(N−1);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
二、解答
import java.util.*;
public class Main{
public static void main(String[] args) {
//Get Data
Scanner sc = new Scanner(System.in);
int cityNum = sc.nextInt();
int roadNum = sc.nextInt();
int sour = sc.nextInt();
int dest = sc.nextInt();
int[][] cityArr = new int[cityNum][cityNum];
int[][] costArr = new int[cityNum][cityNum];
for (int i = 0; i < cityNum; i++) {
for (int j = 0; j < cityNum; j++) {
cityArr[i][j] = cityArr[j][i] = costArr[i][j] = costArr[j][i] = Integer.MAX_VALUE;
}
cityArr[i][i] = costArr[i][i] = 0;
}
for (int i = 0; i < roadNum; i++) {
int a = sc.nextInt(), b = sc.nextInt(), dis = sc.nextInt(), val = sc.nextInt();
cityArr[a][b] = cityArr[b][a] = dis;
costArr[a][b] = costArr[b][a] = val;
}
sc.close();
int[] dis = new int[cityNum];
int[] pri = new int[cityNum];
int[] path = new int[cityNum];
boolean[] coll = new boolean[cityNum];
for (int i = 0; i < cityNum; i++) {
dis[i] = pri[i] = Integer.MAX_VALUE;
path[i] = -1;
}
//Dijkstra
dis[sour] = 0;
pri[sour] = 0;
int cur = sour;
while(cur != -1){
coll[cur] = true;
for (int i = 0; i < cityNum; i++) {
if (cityArr[cur][i] < Integer.MAX_VALUE){
if ((dis[cur] + cityArr[cur][i] < dis[i]) ||
(dis[cur] + cityArr[cur][i] == dis[i] && pri[cur] + costArr[cur][i] < pri[i])
){
dis[i] = dis[cur] + cityArr[cur][i];
pri[i] = pri[cur] + costArr[cur][i];
path[i] = cur;
}
}
}
cur = findNext(dis, coll, pri);
}
System.out.println(dis[dest] + " " + pri[dest]);
}
public static int findNext(int[]dis, boolean[] coll, int[] pri){
int minIndex = -1;
int minPrice = Integer.MAX_VALUE;
int minDis = Integer.MAX_VALUE;
for (int i = 0; i < dis.length; i++) {
if (dis[i] <= minDis && coll[i] == false){
minIndex = i;
minDis = dis[i];
minPrice = pri[i];
}
}
return minIndex;
}
}
思路:
- 这道题是图的什么类型题? 要求得到指定两个点之间的最短路径,显然是单源有权最短路问题,使用Dijkstra
- 虽然本题没有要求输出路径,但此处解法还是去记录了一下路径
- Dijkstra的实现:循环找到未收集过的点中的距离最小值进行收集,比较大小,更新距离
- 路径长度相同,如何找到代价最小的路径:在计算最短路径的同时,也计算最小的开支,只不过优先级为先考虑最短距离,再考虑最小开支,具体查看代码第42行
思考:
最大N,M时运行超时了,估计是因为每次在找距离最小点的时候时间复杂度太高了,网课中推荐最小堆实现