题目描述
周末小明准备去爬山锻炼,0代表平地,山的高度使用1到9来表示,小明每次爬山或下山高度只能相差k及k以内,每次只能上下左右一个方向上移动一格,小明从左上角(0,0)位置出发
输入描述
第一行输入m n k(空格分隔)
- 代表m*n的二维山地图,k为小明每次爬山或下山高度差的最大值,
然后接下来输入山地图,一共m行n列,均以空格分隔。取值范围:
- 0 < m ≤ 500
- 0< n ≤ 500
- 0 < k < 5
输出描述
请问小明能爬到的最高峰多高,到该最高峰的最短步数,输出以空格分隔。
同高度的山峰输出较短步数。
如果没有可以爬的山峰,则高度和步数都返回0。
备注
所有用例输入均为正确格式,且在取值范围内,考生不需要考虑不合法的输入格式。
用例
输入 | 5 4 1 0 1 2 0 1 0 0 0 1 0 1 2 1 3 1 0 0 0 0 9 |
输出 | 2 2 |
说明 | 根据山地图可知,能爬到的最高峰在(0,2)位置,高度为2,最短路径为(0,0)-(0,1)-(0,2),最短步数为2。 |
输入 | 5 4 3 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 9 |
输出 | 0 0 |
说明 | 根据山地图可知,每次爬山距离3,无法爬到山峰上,步数为0。 |
题目解析
本题可以使用广度优先搜索进行解题。
初始时,小明位于(0, 0)位置,此时走的步数step = 0,假设地图为matrix,则到高度matrix[0][0]的最短步数为step=0。
我们可以假设,爬山的最大高度为maxHeight,到达此高度的最小步数为minStep,则初始时,maxHeight = maxtrix[0][0],minStep = 0。
对于任意当前位置(x, y),假设其下一步位置是(newX, newY)
本题需要注意的是:向四个方向进行深搜时,需要注意当前位置的高度值,和下一个位置的高度值,之间的差值需要小于等于k,才能进入下一个位置继续广搜。
如果可以进入下一步,则step++,假设(newX, newY)位置的山高度为curHeight, 则:
- 如果 curHeight > maxHeight 的话,则爬到了更高的山,此时直接更新 maxHeight = curHeight,minStep = step;
- 如果 curHeight == maxHeight 的话,则需要继续比较step和minStep,我们需要保留step和minStep中较小步数作为 maxHeight(==curHeight)山高度的步数。
- 如果 curHeight < maxHeight 的话,则无需处理
在广搜过程,为了避免走回头路,我们应该记录走过的节点,我们可以定义一个visited数组来标记走过的路。
关于广搜的原理,大家可以看:
2023.11.2
输出描述中说:如果没有可以爬的山峰,则高度和步数都返回0。
其中“没有可以爬的山峰”,结合用例2来理解的话,应该是没有可爬的更高的山峰。即当只有可爬平级的山峰,也要高度和步数都返回0。
Java算法源码
import java.util.LinkedList;
import java.util.Scanner;
public class Main {
static int m;
static int n;
static int k;
static int[][] matrix;
static int[][] offsets = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
static int maxHeight;
static int minStep;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
m = sc.nextInt();
n = sc.nextInt();
k = sc.nextInt();
matrix = new int[m][n];
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
matrix[i][j] = sc.nextInt();
}
}
System.out.println(getResult());
}
public static String getResult() {
// 到达matrix[0][0]高度的山峰,最短步数是0
maxHeight = matrix[0][0];
minStep = 0;
// 广搜
bfs();
if (minStep == 0) {
// 输出描述:如果没有可以爬的山峰,则高度和步数都返回0。
return "0 0";
} else {
return maxHeight + " " + minStep;
}
}
public static void bfs() {
// 广搜队列
LinkedList<int[]> queue = new LinkedList<>();
// 访问记录
boolean[][] visited = new boolean[m][n];
// 首先是(0,0)位置进入队列,且被标记为访问过
queue.add(new int[] {0, 0});
visited[0][0] = true;
// 此时消耗步数为0
int step = 0;
while (queue.size() > 0) {
// 这里没有用queue.removeFirst来控制广搜,而是使用newQueue来控制广搜,因为这样更方便操作step
LinkedList<int[]> newQueue = new LinkedList<>();
step++;
// 遍历同一层的所有节点
for (int[] lastPos : queue) {
int x = lastPos[0];
int y = lastPos[1];
int lastHeight = matrix[x][y];
// 四个方向位置
for (int[] offset : offsets) {
int newX = x + offset[0];
int newY = y + offset[1];
// 新位置越界则无法继续广搜
if (newX < 0 || newX >= m || newY < 0 || newY >= n) continue;
// 新位置已访问过,则无需重复广搜
if (visited[newX][newY]) continue;
int curHeight = matrix[newX][newY];
// 前后位置高度差在k以内, 则可以进入新位置
if (Math.abs(curHeight - lastHeight) <= k) {
// 标记新位置已访问
visited[newX][newY] = true;
// 如果此时到达新位置高度的步数step更小,则更新对应高度的最小步数
if (curHeight > maxHeight || (curHeight == maxHeight && step < minStep)) {
maxHeight = curHeight;
minStep = step;
}
// 新位置加入下一层广搜队列
newQueue.add(new int[] {newX, newY});
}
}
}
queue = newQueue;
}
}
}
JS算法源码
const rl = require("readline").createInterface({ input: process.stdin });
var iter = rl[Symbol.asyncIterator]();
const readline = async () => (await iter.next()).value;
void (async function () {
// Write your code here
const [m, n, k] = (await readline()).split(" ").map(Number);
const matrix = [];
for (let i = 0; i < m; i++) {
matrix.push((await readline()).split(" ").map(Number));
}
const offsets = [
[-1, 0],
[1, 0],
[0, -1],
[0, 1],
];
// 到达matrix[0][0]高度的山峰,最短步数是0
let maxHeight = matrix[0][0];
let minStep = 0;
// 广搜
bfs();
if (minStep == 0) {
// 输出描述:如果没有可以爬的山峰,则高度和步数都返回0。
console.log("0 0");
} else {
console.log(maxHeight + " " + minStep);
}
function bfs() {
// 广搜队列
let queue = [];
// 访问记录
const visited = new Array(m).fill(0).map(() => new Array(n).fill(false));
// 首先是(0,0)位置进入队列,且被标记为访问过
queue.push([0, 0]);
visited[0][0] = true;
// 此时消耗步数为0
let step = 0;
while (queue.length > 0) {
// 这里没有用queue.removeFirst来控制广搜,而是使用newQueue来控制广搜,因为这样更方便操作step
const newQueue = [];
step++;
// 遍历同一层的所有节点
for (let [x, y] of queue) {
const lastHeight = matrix[x][y];
// 四个方向位置
for (let [offsetX, offsetY] of offsets) {
const newX = x + offsetX;
const newY = y + offsetY;
// 新位置越界则无法继续广搜
if (newX < 0 || newX >= m || newY < 0 || newY >= n) continue;
// 新位置已访问过,则无需重复广搜
if (visited[newX][newY]) continue;
const curHeight = matrix[newX][newY];
// 前后位置高度差在k以内, 则可以进入新位置
if (Math.abs(curHeight - lastHeight) <= k) {
// 标记新位置已访问
visited[newX][newY] = true;
// 如果此时到达新位置高度的步数step更小,则更新对应高度的最小步数
if (
curHeight > maxHeight ||
(curHeight == maxHeight && step < minStep)
) {
maxHeight = curHeight;
minStep = step;
}
// 新位置加入下一层广搜队列
newQueue.push([newX, newY]);
}
}
}
queue = newQueue;
}
}
})();
Python算法源码
# 输入获取
m, n, k = map(int, input().split())
matrix = [list(map(int, input().split())) for _ in range(m)]
offsets = ((-1, 0), (1, 0), (0, -1), (0, 1))
# 到达matrix[0][0]高度的山峰,最短步数是0
maxHeight = matrix[0][0]
minStep = 0
def bfs():
global maxHeight, minStep
# 广搜队列
queue = []
# 访问记录
visited = [[False] * n for _ in range(m)]
# 首先是(0,0)位置进入队列,且被标记为访问过
queue.append((0, 0))
visited[0][0] = True
# 此时消耗步数为0
step = 0
while len(queue) > 0:
# 这里没有用queue.removeFirst来控制广搜,而是使用newQueue来控制广搜,因为这样更方便操作step
newQueue = []
step += 1
# 遍历同一层的所有节点
for x, y in queue:
lastHeight = matrix[x][y]
# 四个方向位置
for offsetX, offsetY in offsets:
newX = x + offsetX
newY = y + offsetY
# 新位置越界则无法继续广搜
if newX < 0 or newX >= m or newY < 0 or newY >= n:
continue
# 新位置已访问过,则无需重复广搜
if visited[newX][newY]:
continue
curHeight = matrix[newX][newY]
# 前后位置高度差在k以内, 则可以进入新位置
if abs(curHeight - lastHeight) <= k:
visited[newX][newY] = True
# 如果此时到达新位置高度的步数step更小,则更新对应高度的最小步数
if curHeight > maxHeight or (curHeight == maxHeight and step < minStep):
maxHeight = curHeight
minStep = step
# 新位置加入下一层广搜队列
newQueue.append((newX, newY))
queue = newQueue
# 算法入口
def getResult():
# 广搜
bfs()
if minStep == 0:
# 输出描述:如果没有可以爬的山峰,则高度和步数都返回0。
return "0 0"
else:
return f"{maxHeight} {minStep}"
# 算法调用
print(getResult())
C算法源码
#include <stdio.h>
#include <stdlib.h>
#define MAX_SIZE 500
typedef struct ListNode {
int ele;
struct ListNode *prev;
struct ListNode *next;
} ListNode;
typedef struct {
int size;
ListNode *head;
ListNode *tail;
} LinkedList;
LinkedList *new_LinkedList();
void addLast_LinkedList(LinkedList *link, int ele);
int m, n, k;
int matrix[MAX_SIZE][MAX_SIZE] = {0};
int visited[MAX_SIZE][MAX_SIZE] = {0};
int offsets[4][2] = {{-1, 0},
{1, 0},
{0, -1},
{0, 1}};
int maxHeight;
int minStep;
int getResult();
void bfs();
int main() {
scanf("%d %d %d", &m, &n, &k);
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
scanf("%d", &matrix[i][j]);
}
}
// 到达matrix[0][0]高度的山峰,最短步数是0
maxHeight = matrix[0][0];
minStep = 0;
// 广搜
bfs();
if (minStep == 0) {
// 输出描述:如果没有可以爬的山峰,则高度和步数都返回0。
puts("0 0");
} else {
printf("%d %d", maxHeight, minStep);
}
return 0;
}
void bfs() {
// 广搜队列
LinkedList *queue = new_LinkedList();
// 首先是(0,0)位置进入队列,且被标记为访问过
addLast_LinkedList(queue, 0 * n + 0);
visited[0][0] = 1;
// 此时消耗步数为0
int step = 0;
while (queue->size > 0) {
// 这里没有用queue.removeFirst来控制广搜,而是使用newQueue来控制广搜,因为这样更方便操作step
LinkedList *newQueue = new_LinkedList();
step++;
// 遍历同一层的所有节点
ListNode *cur = queue->head;
while (cur != NULL) {
int x = cur->ele / n;
int y = cur->ele % n;
int lastHeight = matrix[x][y];
// 四个方向位置
for (int i = 0; i < 4; i++) {
int newX = x + offsets[i][0];
int newY = y + offsets[i][1];
// 新位置越界则无法继续广搜
if (newX < 0 || newX >= m || newY < 0 || newY >= n) continue;
// 新位置已访问过,则无需重复广搜
if (visited[newX][newY]) continue;
// 前后位置高度差在k以内, 则可以进入新位置
int curHeight = matrix[newX][newY];
if (abs(curHeight - lastHeight) <= k) {
// 标记新位置已访问
visited[newX][newY] = 1;
// 如果此时到达新位置高度的步数step更小,则更新对应高度的最小步数
if (curHeight > maxHeight || (curHeight == maxHeight && step < minStep)) {
maxHeight = curHeight;
minStep = step;
}
// 新位置加入下一层广搜队列
addLast_LinkedList(newQueue, newX * n + newY);
}
}
cur = cur->next;
}
queue = newQueue;
}
}
LinkedList *new_LinkedList() {
LinkedList *link = (LinkedList *) malloc(sizeof(LinkedList));
link->size = 0;
link->head = NULL;
link->tail = NULL;
return link;
}
void addLast_LinkedList(LinkedList *link, int ele) {
ListNode *node = (ListNode *) malloc(sizeof(ListNode));
node->ele = ele;
node->prev = NULL;
node->next = NULL;
if (link->size == 0) {
link->head = node;
link->tail = node;
} else {
link->tail->next = node;
node->prev = link->tail;
link->tail = node;
}
link->size++;
}
免责声明:
1、IT资源小站为非营利性网站,全站所有资料仅供网友个人学习使用,禁止商用
2、本站所有文档、视频、书籍等资料均由网友分享,本站只负责收集不承担任何技术及版权问题
3、如本帖侵犯到任何版权问题,请立即告知本站,本站将及时予与删除下载链接并致以最深的歉意
4、本帖部分内容转载自其它媒体,但并不代表本站赞同其观点和对其真实性负责
5、一经注册为本站会员,一律视为同意网站规定,本站管理员及版主有权禁止违规用户
6、其他单位或个人使用、转载或引用本文时必须同时征得该帖子作者和IT资源小站的同意
7、IT资源小站管理员和版主有权不事先通知发贴者而删除本文
评论0