最新华为OD机试
题目描述
有一辆汽车需要从 m * n 的地图左上角(起点)开往地图的右下角(终点),去往每一个地区都需要消耗一定的油量,加油站可进行加油。
请你计算汽车确保从从起点到达终点时所需的最少初始油量。
说明:
- 智能汽车可以上下左右四个方向移动
- 地图上的数字取值是 0 或 -1 或 正整数:
- -1 :表示加油站,可以加满油,汽车的油箱容量最大为100;
- 0 :表示这个地区是障碍物,汽车不能通过
- 正整数:表示汽车走过这个地区的耗油量
- 如果汽车无论如何都无法到达终点,则返回 -1
输入描述
第一行为两个数字,M,N,表示地图的大小为 M * N
- 0 < M,N ≤ 200
后面一个 M * N 的矩阵,其中的值是 0 或 -1 或正整数,加油站的总数不超过 200 个
输出描述
如果汽车无论如何都无法到达终点,则返回 -1
如果汽车可以到达终点,则返回最少的初始油量
示例1
输入
2,2
10,20
30,40
123
输出
70
1
说明
行走的路线为:右→下
示例2
输入
4,4
10,30,30,20
30,30,-1,10
0,20,20,40
10,-1,30,40
12345
输出
70
1
说明
行走的路线为:右→右→下→下→下→右
示例3
输入
4,5
10,0,30,-1,10
30,0,20,0,20
10,0,10,0,30
10,-1,30,0,10
12345
输出
60
1
说明
行走的路线为:下→下→下→右→右→上→上→上→右→右→下→下→下
示例4
输入
4,4
10,30,30,20
30,30,20,10
10,20,10,40
10,20,30,40
12345
输出
-1
1
说明
无论如何都无法到达终点
解题思路
Java
import java.util.*;
public class Main {
// 定义常量,表示汽车油箱的最大容量
private static final int MAX_FUEL = 100;
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in).useDelimiter(",|\\s+");
// 读取地图的行数和列数
int numRows = scanner.nextInt();
int numCols = scanner.nextInt();
// 创建地图数组
int[][] map = new int[numRows][numCols];
// 填充地图数组,读取每个单元的值
for (int i = 0; i < numRows; i++) {
for (int j = 0; j < numCols; j++) {
map[i][j] = scanner.nextInt();
}
}
// 计算并获取最小初始油量
int minFuel = findMinimumInitialFuel(map, numRows, numCols);
// 输出计算结果
System.out.println(minFuel);
}
// 使用二分查找方法确定从起点到终点所需的最小初始油量
private static int findMinimumInitialFuel(int[][] map, int numRows, int numCols) {
int low = 0, high = MAX_FUEL, optimalFuel = -1; // 初始化二分查找的上下界及结果
while (low <= high) {
int mid = (low + high) / 2;
// 判断当前中值油量是否足以到达终点
if (canReachDestination(map, mid, numRows, numCols)) {
optimalFuel = mid; // 更新找到的可行油量
high = mid - 1; // 尝试寻找更小的可行油量
} else {
low = mid + 1; // 增加油量尝试
}
}
return optimalFuel; // 返回最小初始油量,如果无法到达则返回-1
}
// 检查给定起始油量是否足以从起点到达终点
private static boolean canReachDestination(int[][] map, int startFuel, int numRows, int numCols) {
if (map[0][0] == 0) return false; // 起点如果是障碍物,则无法出发
// 初始化每个位置的剩余油量数组
int[][] remainingFuel = new int[numRows][numCols];
for (int[] row : remainingFuel) {
Arrays.fill(row, -1);
}
// 设置起点的初始油量
remainingFuel[0][0] = map[0][0] == -1 ? MAX_FUEL : startFuel - map[0][0];
if (remainingFuel[0][0] < 0) return false; // 如果起始油量不足以离开起点,返回false
// 使用优先队列按照油量从大到小进行搜索
PriorityQueue<int[]> priorityQueue = new PriorityQueue<>((a, b) -> b[2] - a[2]);
priorityQueue.offer(new int[]{
0, 0, remainingFuel[0][0]});
int[] dx = {
0, 1, 0, -1}; // 搜索方向数组x
int[] dy = {
1, 0, -1, 0}; // 搜索方向数组y
// BFS搜索
while (!priorityQueue.isEmpty()) {
int[] current = priorityQueue.poll();
int currentRow = current[0], currentCol = current[1], fuel = current[2];
if (currentRow == numRows - 1 && currentCol == numCols - 1) return true; // 如果到达终点,则返回true
// 检查四个方向
for (int direction = 0; direction < 4; direction++) {
int newRow = currentRow + dx[direction], newCol = currentCol + dy[direction];
if (isValid(newRow, newCol, numRows, numCols, map)) {
// 检查新位置是否有效
int newFuel = map[newRow][newCol] == -1 ? MAX_FUEL : fuel - map[newRow][newCol];
if (newFuel > remainingFuel[newRow][newCol]) {
remainingFuel[newRow][newCol] = newFuel;
priorityQueue.offer(new int[