问题描述
小C和他的领导小F计划一次飞行,但由于严格的航空管制,他们的飞机仅能按特定的路线飞行:飞机只能飞往当前机场的相邻机场或相同航空公司管理的机场。为了减少起飞次数,小C需要制定最优的飞行路线。机场由一个数组airports标识,其中:
- 数组每个元素代表一个独特的机场,元素的值代表不同的航空公司。
airports[0]为起点,airports[airports.length - 1]为终点。- 假设小C当前在机场
i,那么i - 1和i + 1(如果存在)代表邻近机场,飞机可以直接前往。 - 如果在机场
i,且存在airports[i] == airports[j],则机场i和机场j同属一家航空公司,可直接飞往。
求最小起飞次数。
测试样例
样例1:
输入:
airports = [10, 12, 13, 12, 14]
输出:3
样例2:
输入:
airports = [10, 11, 12, 13, 14]
输出:4
样例3:
输入:
airports = [7, 7, 7, 8, 9, 7]
输出:1
求解思路
这题首先分析题目,题目中提到,对于当前机场 i, i-1 和 i+1 机场(如果存在)以及值 airports[i] = airport[j] (如果存在)的机场可以直接飞往。这就表示索引相邻和值相同的机场是相邻的。因此这里可以将输入的数组转换成一个图存储。
图存储
对于样例1:airports[0]的邻接点为airports[1];airports[1]的邻接点为airports[0],airports[2],airports[3];airports[2]的邻接点为airports[1]和airports[3];airports[3]的邻接点为airports[1],airports[2]和airports[4];airports[4]的邻接点为airports[3]。邻接矩阵来表示为:
[[0,1,0,0,0], [1,0,1,1,0], [0,1,0,1,0], [0,1,1,0,1], [0,0,0,1,0]]
图的最短路径问题
得到邻接矩阵后,问题就转换成我们需要得到的是 0 到 airports.length-1的最短路径,对于图的最短路径问题有很多解决方法。
- 如果是无权图,可以直接使用BFS广度优先遍历方法找到最短路径。
- 如果是非负有权图,可以使用迪杰斯特拉算法,是通过贪心算法来找到某一个结点到任意一个结点的最短路径。
- 如果需要找任意两个结点之间的最短路径,可以用Floyd算法。
这题我们直接用BFS方法。
BFS遍历
用一个队列记录待遍历结点,广度优先遍历每次遍历一个结点,则将与该结点相邻并且没有被放入队列中的邻接结点放入到待遍历队列中。直到遍历到需要的结点。
- 将 i=0 放入队列中。
- 用 visited 数组记录已经放入队列的结点。visited[0] = 1。
- 用 parents 数组记录每个结点的父节点。
- 遍历队列,每次将头结点相邻并且没有被放入队列中的邻接结点放入到队尾。visited[j] = 1;parents[j] = queue[0]。
- 删除头结点,重复第四步,直到遍历到 length-1,并且得到的一定是最短路径。
根据parents记录的每个结点的父节点,可以得到从 0 到 length-1 的路线,记录路线的结点数,即为最终的答案。
完整代码如下
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Main {
public static int solution(int[] airports) {
// 邻接矩阵
int [][]Graph = new int[airports.length][airports.length];
for(int[] row: Graph)
Arrays.fill(row, 0);
// 初始化
for(int i=0; i<airports.length; i++){
for(int j=0; j<airports.length; j++){
if(j==i-1)
Graph[i][j] = 1; // 前一个机场直达
if(j==i+1)
Graph[i][j] = 1; // 后一个机场直达
if(airports[i] == airports[j])
Graph[i][j] = 1; // 同公司机场直达
}
}
// BFS搜索
int[] visited = new int[airports.length];
int[] parent = new int[airports.length];
Arrays.fill(visited, 0);
List<Integer> queue = new ArrayList<>();
queue.add(0);
parent[0] = -1;
visited[0] = 1;
while(queue.size() > 0 && queue.get(0)!= airports.length-1){
for(int i=0; i<airports.length; i++){
if(Graph[queue.get(0)][i] == 1 && visited[i] == 0){
queue.add(i);
visited[i] = 1;
parent[i] = queue.get(0);
}
}
queue.remove(0);
}
// 输出结果
int count=0;
int index = airports.length-1;
while(index!= -1){
count++;
index = parent[index];
}
return count-1;
}
public static void main(String[] args) {
// You can add more test cases here
int[] airports1 = {10, 12, 13, 12, 14};
int[] airports2 = {10, 11, 12, 13, 14};
System.out.println(solution(airports1) == 3);
System.out.println(solution(airports2) == 4);
}
}
问题总结
本题实际上考察图的最短路径问题,对于无权图,直接用BFS就可以求得最短路径,作为学习,可以尝试迪杰斯特拉算法或者Floyd算法来解决问题。另一方面对于图的创建,代码中使用邻接矩阵来表示图结构,当然也可以用邻接链表的格式来表示图结构。