注意事项
本文包括社招题库中的较困难题目,如华为OD中分值为200的题目
回溯 勇攀数字高峰
题目描述
你在给定的数字地形图中寻找登山路径,数字代表当前位置的海拔高度,要求从最低海拔出发,不断攀登,最终到达最高山峰,你需要寻找所有满足条件的登山路径。地图 保证最低海拔和最高山峰只有一个。
路径条件
登山规则 :路径海拔必须严格递增
移动限制 :可以上下左右四个方向 移动
路径限制 :路径必须从最低海拔开始,到最高海拔结束
访问限制 :每个地点只能走一次
高度差限制 :每一个攀登高度必须大于 0,小于等于指定值。
输入描述
输入一个二维数组 表示的海拔图,维度 n * m (2 <= n, m <= 10) 输入一个整数,参数表示单步最大允许的高度差
输出描述
输出满足条件的登山路径的数量
用例1
1 2 3 4 5 6 7 8 9 输入: 4 4 5 7 6 4 5 9 5 1 1 2 4 1 4 1 3 2 0 输出: 2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 package b_hard;import java.util.*;public class b01_climbing_the_digital_summit { static int [] dx = {1 , -1 , 0 , 0 }; static int [] dy = {0 , 0 , 1 , -1 }; static boolean [][] visited = new boolean [15 ][15 ]; static int sx, sy, ex, ey; public static int dfs (int x, int y, int n, int m, int k, int [][] grid) { if (x == ex && y == ey) { return 1 ; } visited[x][y] = true ; int res = 0 ; for (int i = 0 ; i < 4 ; i++) { int nx = x + dx[i]; int ny = y + dy[i]; if (nx < 0 || nx >= n || ny < 0 || ny >= m) continue ; if (visited[nx][ny]) continue ; int diff = grid[nx][ny] - grid[x][y]; if (diff > 0 && diff <= k) { res += dfs(nx, ny, n, m, k, grid); } } visited[x][y] = false ; return res; } public static int cal (int n, int m, int k, int [][] grid) { int minVal = Integer.MAX_VALUE, maxVal = Integer.MIN_VALUE; for (int i = 0 ; i < n; i++) { for (int j = 0 ; j < m; j++) { if (grid[i][j] < minVal) { minVal = grid[i][j]; sx = i; sy = j; } if (grid[i][j] > maxVal) { maxVal = grid[i][j]; ex = i; ey = j; } } } return dfs(sx, sy, n, m, k, grid); } public static void main (String[] args) { Scanner sc = new Scanner (System.in); int n = sc.nextInt(); int m = sc.nextInt(); int k = sc.nextInt(); int [][] grid = new int [n][m]; for (int i = 0 ; i < n; i++) { for (int j = 0 ; j < m; j++) { grid[i][j] = sc.nextInt(); } } System.out.println(cal(n, m, k, grid)); } }
广度优先搜索(BFS) 直捣黄龙
题目描述 小王在玩一款叫做直捣黄龙的小游戏,在该游戏中他需要从入口位置进入敌营,绕过哨兵的层层封锁,达到敌军司令部实施斩首行动。 敌军阵营是一个 n*n 的矩阵,入口在坐标 (0, n/2),敌军司令部在坐标 (n-1, n/2),每个哨兵警戒以自己为中心的9宫格,一旦被哨兵发现则行动失败。同时穿越敌营耗时越长,被发现的概率越高,因此小王需要寻找到可以绕过警戒到达敌军司令部的最短路径。请你设计一个小程序,帮助小王统计这样的路径有多少条,以及路径长度。
规则说明:
其中 n 为大于 1 的奇数且取值小于 30,坐标 x,y 取值均从 0 开始,敌营左下角定义为 (0,0),右上角定义为 (n-1,n-1)
敌营入口在坐标 (0, n/2),敌军司令部在坐标 (n-1, n/2)。
游戏角色的行动方向只包含上、下、左、右四个方向,即一次行动 x、y坐标不可同时变化。
在没有满足题目要求的可达路径时,需要返回0 0。
输入描述 参数 1,敌军阵营的边长 n。 参数 2,哨兵位置列表 Point{x,y}:x 未行坐标,y 为列坐标。x和y以逗号分割,不同坐标以空格分割
输出描述 输出两个成员空格分割,第一个成员为最短路径条数,第二个成员为最短路径长度。
用例1
1 2 3 4 5 6 7 8 9 10 11 12 输入: 5 2,2 输出: 2 9 说明: 两条最短路径,S 表示哨兵位置,A 表示起点,E 表示终点 路径1:[(0,2),(0,1),(0,0),(1,0),(2,0),(3,0),(4,0),(4,1),(4,2)] 路径2:[(0,2),(0,3),(0,4),(1,4),(2,4),(3,4),(4,4),(4,3),(4,2)] 因此返回为2 9
用例2
1 2 3 4 5 6 7 8 9 输入: 3 1,1 输出: 0 0 说明: 无路径场景,S 表示哨兵位置,A 表示起点,E 表示终点,哨兵警戒了全图
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 package b_hard;import java.util.*;class Point { int x, y; Point(int xx, int yy) { x = xx; y = yy; } } public class b02_storm_the_enemy_den { public static void main (String[] args) { Scanner sc = new Scanner (System.in); int n = sc.nextInt(); sc.nextLine(); String line = sc.nextLine(); List<Point> points = new ArrayList <>(); for (String s : line.split(" " )) { String[] rowCol = s.split("," ); points.add(new Point (Integer.parseInt(rowCol[0 ]), Integer.parseInt(rowCol[1 ]))); } int [] res = calShortestPath(n, points); System.out.println(res[0 ] + " " + res[1 ]); } static int [] calShortestPath(int n, List<Point> points) { int [][] grid = new int [n][n]; for (Point point : points) { int x = point.x; int y = point.y; for (int i = x - 1 ; i <= x + 1 ; i++) { for (int j = y - 1 ; j <= y + 1 ; j++) { if (i < 0 || i >= n || j < 0 || j >= n) continue ; grid[i][j] = -1 ; } } } int [][] dirs = {{1 , 0 }, {-1 , 0 }, {0 , 1 }, {0 , -1 }}; int sx = 0 , sy = n / 2 ; int ex = n - 1 , ey = n / 2 ; if (grid[sx][sy] == -1 || grid[ex][ey] == -1 ) return new int []{0 , 0 }; int [][] dist = new int [n][n]; int [][] distNum = new int [n][n]; for (int [] row : dist) Arrays.fill(row, -1 ); Queue<int []> q = new LinkedList <>(); q.offer(new int []{sx, sy}); dist[sx][sy] = 1 ; distNum[sx][sy] = 1 ; while (!q.isEmpty()) { int [] p = q.poll(); int x = p[0 ], y = p[1 ]; for (int [] d : dirs) { int nx = x + d[0 ]; int ny = y + d[1 ]; if (nx < 0 || nx >= n || ny < 0 || ny >= n || grid[nx][ny] == -1 ) continue ; if (dist[nx][ny] == -1 ) { dist[nx][ny] = dist[x][y] + 1 ; distNum[nx][ny] = distNum[x][y]; q.offer(new int []{nx, ny}); } else if (dist[x][y] + 1 == dist[nx][ny]) { distNum[nx][ny] += distNum[x][y]; } } } if (dist[ex][ey] == -1 ) return new int []{0 , 0 }; return new int []{distNum[ex][ey], dist[ex][ey]}; } }
过程演示