7-9 旅游规划(25 分)
有了一张自驾旅游路线图,你会知道城市间的高速公路长度、以及该公路要收取的过路费。现在需要你写一个程序,帮助前来咨询的游客找一条出发地和目的地之间的最短路径。如果有若干条路径都是最短的,那么需要输出最便宜的一条路径。
输入格式:
输入说明:输入数据的第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
思路:
1、就是在Floyd算法的基础上修改一下。
2、有两个权重矩阵,最优先的是路径长度,在相同的路径长度下,再选择最便宜的价格。
3、当增加k点后路径较短时,同时更新路径权重矩阵,与价格权重矩阵。
4、回想一下在线处理的思想,当G[i][k] + G[k][j] = G[i][j]的时候,这时比较ik的价格与kj的价格之和与ij的价格。选择较小的那个更新价格矩阵。
%%%%%%%%%%%%%%%%%%%%分割线%%%%%%%%%%%%%%%%%%%%%%%
后来又听了陈越姥姥的讲解。发现自己的方法用复杂了,其实不用计算任意两点的结果,只需要计算题目给定的两个点即可,也就是单点有权最短路径问题,就是Dijstra算法的修改,当等于的时候,就只更新价格权重数组即可,思路都是一样的,不过单点的话时间复杂度是O(V^2+E),多点是O(V^3)。
注意几点Dilstra算法的几个小细节:
1、如果把原点作为没收录的第一个点,想想需不需要把图对角矩阵的对角线初始化为0,具体问题具体分析,没有统一答案。
2、从dist数组中选择未收录的最小值,注意未收录,可以直接遍历,也可以用最小堆,整体时间复杂度不一样,分别适用于稠密图和稀疏图。
3、对于V,循环的具体流程是先收录进去,然后 判断V的没有被收录进去的邻接点。更新数组。
第一个程序是Floyd算法的修改;
第二个是Dilstra算法的修改;
import java.util.Scanner;
public class Main {
static int N;
static int M;
static int S;
static int D;
static int G[][];
static int P[][];
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner in = new Scanner(System.in);
N = in.nextInt();
M = in.nextInt();
S = in.nextInt();
D = in.nextInt();
G = new int[N][N];
P = new int[N][N];
int path[][] = new int[N][N];
for(int i = 0;i<N;i++)
for(int j = 0; j<N;j++) {
G[i][j] = Integer.MAX_VALUE/100;
P[i][j] = Integer.MAX_VALUE/100;
}
for(int i =0;i<M;i++) {
int x = in.nextInt();
int y = in.nextInt();
G[x][y] = in.nextInt();
G[y][x] = G[x][y];
P[x][y] = in.nextInt();
P[y][x] = P[x][y];
}
// for(int k = 0;k<N;k++)
// for(int i = 0; i<N;i++)
// for(int j = 0;j<N;j++) {
// if(P[i][k]+P[k][j]<P[i][j])
// P[i][j] = P[i][k]+P[k][j];
// }
//
//
for(int k = 0;k<N;k++)
for(int i = 0; i<N;i++)
for(int j = 0;j<N;j++) {
if(G[i][k]+G[k][j]<G[i][j]) {
G[i][j] = G[i][k]+G[k][j];
P[i][j] = P[i][k]+P[k][j];
path[i][j] = k;
}
else if(G[i][k]+G[k][j] == G[i][j]) {
int tp1 = P[i][j];
int tp2 = P[i][k]+ P[k][j];
if(tp1>tp2) {
path[i][j] = k;
P[i][j] = P[i][k]+P[k][j];
}
}
}
System.out.print(G[S][D]+" "+P[S][D]);
}
}
import java.util.Scanner;
public class Main {
static int N;
static int M;
static int S;
static int D;
static int G[][];
static int P[][];
static int dist[];
static int price[];
static boolean collected[];
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner in = new Scanner(System.in);
N = in.nextInt();
M = in.nextInt();
S = in.nextInt();
D = in.nextInt();
collected = new boolean[N];
G = new int[N][N];
P = new int[N][N];
price = new int[N];
dist = new int[N];
for(int i =0;i<N;i++) {
dist[i] = Integer.MAX_VALUE/10;
price[i] = Integer.MAX_VALUE/10;
}
dist[S] = 0;
price[S] = 0;
for(int i =0;i<N;i++)
for(int j =0;j<N;j++) {
G[i][j] = Integer.MAX_VALUE/10;
P[i][j] = Integer.MAX_VALUE/10;
if(j==i) {
G[i][j] = 0;
P[i][j] = 0;
}
}
for(int i =0;i<M;i++) {
int x = in.nextInt();
int y = in.nextInt();
G[x][y] = in.nextInt();
G[y][x] = G[x][y];
P[x][y] = in.nextInt();
P[y][x] = P[x][y];
}
while(true) {
int V = min_dist();
if(V == -1)
break;
collected[V] = true;
for(int W = 0;W<N;W++) {
if(G[V][W]<Integer.MAX_VALUE/10&&collected[W]==false)
{
if(dist[W]>G[V][W]+dist[V]) {
dist[W] = dist[V]+G[V][W];
price[W] = price[V]+P[V][W];
}
else if(dist[W]==G[V][W]+dist[V]) {
if(price[V]+P[V][W]<price[W]) {
price[W] = price[V]+P[V][W];
}
}
}
}
}
System.out.print(dist[D]+" "+price[D]);
}
private static int min_dist() {
// TODO Auto-generated method stub
int temp = Integer.MAX_VALUE/10;
int count = -1;
for(int i = 0;i<N;i++) {
if(dist[i]<temp&&collected[i]==false) {
temp = dist[i];
count = i;
}
}
return count;
}
}