一、题目描述
H城是一个旅游胜地,每年都有成千上万的人前来观光。
为方便游客,巴士公司在各个旅游景点及宾馆,饭店等地都设置了巴士站并开通了一些单程巴士线路。
每条单程巴士线路从某个巴士站出发,依次途经若干个巴士站,最终到达终点巴士站。
一名旅客最近到H城旅游,他很想去S公园游玩,但如果从他所在的饭店没有一路巴士可以直接到达S公园,则他可能要先乘某一路巴士坐几站,再下来换乘同一站台的另一路巴士, 这样换乘几次后到达S公园。
现在用整数1,2,…N 给H城的所有的巴士站编号,约定这名旅客所在饭店的巴士站编号为1,S公园巴士站的编号为N。
写一个程序,帮助这名旅客寻找一个最优乘车方案,使他在从饭店乘车到S公园的过程中换乘的次数最少。
输入格式
- 第一行有两个数字M和N,表示开通了M条单程巴士线路,总共有N个车站。
- 从第二行到第M+1行依次给出了第1条到第M条巴士线路的信息,其中第i+1行给出的是第i条巴士线路的信息,从左至右按运行顺序依次给出了该线路上的所有站号,相邻两个站号之间用一个空格隔开。
输出格式
- 共一行,如果无法乘巴士从饭店到达S公园,则输出”NO”,否则输出最少换乘次数,换乘次数为0表示不需换车即可到达。
数据范围
- 1≤M≤100,
1≤N≤500
输入样例:
3 7
6 7
4 7 3 6
2 1 3 5
输出样例:
2
二、题解
方法一:spfa
注意:这题的输入有点不一样,输入的是 E 串一连串的数,而如果直接用 sc.next() 来读取的话,得到的只有一串连续的数字,所以需要读入字符串然后用 split(" ")
分开。
思路
这题考点是建图,数据可抽象为边权为 1,各车站互联成为错杂交错的路线图。
每一条线路中的每一个车站两两之间构成了一个边权为 1 的连通块,为什么呢?因为一条线路上的车不需要换乘,那么他们虽然看起来距离不一,但在我们的图中,我们只认为换乘才会使距离 +1,所以这就变成为最短路问题啦…
最后的减 dist[V] - 1
是怎么回事呢?因为我们第一次上车是不计入换乘次数内的,但为了方便,我们使边权为 1,V 离 1 的最短距离是 换乘次数 +1
import java.util.*;
import java.math.*;
import java.io.*;
public class Main{
static Edge[] e;
static int[] dist, head;
static boolean[] inq;
static int tot;
static int INF = 0x3f3f3f3f;
static int maxv = 3000 + 50, maxe = 20000 + 50;
static class Edge {
int to, w, next;
Edge() {}
}
static void addEdge(int u, int v, int w) {
e[++tot] = new Edge();
e[tot].to = v;
e[tot].w = w;
e[tot].next = head[u];
head[u] = tot;
}
static void spfa(int S) {
Arrays.fill(dist, INF);
dist[S] = 0;
ArrayDeque<Integer> q = new ArrayDeque<>();
q.add(S);
inq[S] = true;
while (!q.isEmpty()) {
int v = q.poll();
inq[v] = false;
for (int i = head[v]; i != 0; i = e[i].next) {
int to = e[i].to, w = e[i].w;
if (dist[to] > dist[v] + w) {
dist[to] = dist[v] + w;
if (inq[to])
continue;
if (!q.isEmpty() && dist[to] < dist[q.peek()]) {
q.addFirst(to);
} else {
q.add(to);
}
inq[to] = true;
}
}
}
}
public static void main(String[] args) throws IOException {
Scanner sc = new Scanner(new BufferedInputStream(System.in));
BufferedWriter w = new BufferedWriter(new OutputStreamWriter(System.out));
String[] ss = sc.nextLine().split(" ");
int E = Integer.parseInt(ss[0]);
int V = Integer.parseInt(ss[1]);
dist = new int[maxv];
e = new Edge[maxe];
inq = new boolean[maxv];
head = new int[maxv];
while (E-- > 0) {
String[] s = sc.nextLine().split(" ");
int[] dig = new int[s.length];
for (int i = 0; i < s.length; i++) {
dig[i] = Integer.parseInt(s[i]);
}
for (int i = 0; i < dig.length; i++) {
for (int j = i+1; j < dig.length; j++)
addEdge(dig[i], dig[j], 1);
}
}
spfa(1);
System.out.println(dist[V] == INF ? "NO" : dist[V]-1);
}
}
复杂度分析
- 时间复杂度: ,
- 空间复杂度: ,
方法二:临界矩阵存图
void spfa(int S) {
Arrays.fill(dist, INF);
dist[S] = 0;
ArrayDeque<Integer> q = new ArrayDeque<>();
q.add(S);
inq[S] = true;
while (!q.isEmpty()) {
int v = q.poll();
for (int i = 1; i <= V; i++) {
if (g[v][i] && dist[i] > dist[v] + 1) {
dist[i] = dist[v] + 1;
q.add(i);
inq[i] = true;
}
}
}
}