思路:很明显可以使用dfs和bfs,这里我选择dfs,当然还有一点小技巧,比如当到达B楼时接收的按钮次数ans都是目前为止的最小值;比如还没到达B楼时,但此时的按钮次数sum已经大于等于之前已经走到B楼的走法的ans,就可以断定这不是最佳走法,直接return即可。相反,如果不加这些判断条件,很可能会TLE甚至栈溢出!
代码里得解释还是很详细的:
package search;
import java.util.Scanner;
public class P1135 {
static int N, A, B, ans = 999999999;//ans记录最佳最少按按钮得次数,初始值设大点,方便后面比较
static int[] arr;
static boolean[] vis;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
N = sc.nextInt();
A = sc.nextInt();
B = sc.nextInt();
arr = new int[N + 1];
vis = new boolean[N + 1];
for (int i = 1; i <= N; i++) {
arr[i] = sc.nextInt();
}
dfs(A, B, 0);
if (ans != 999999999) {
System.out.println(ans);
}else {
System.out.println(-1);
}
}
// 深搜
/**
* vis存在的意义:因为从A到B有不同的走法,且同一种走法中不能经过相同的楼层,如果经过相同的楼层就说明是另一种走法,因此选择vis记录下一个要走的位置上一次有没有走过
* @param start 从哪开始
* @param end 到哪开始
* @param sum 走到第start楼时已经按了的按钮的次数
*/
public static void dfs(int start, int end, int sum) {
if (start == end) {//如果到达了B楼,就记录目前为止最小的按按钮次数为ans,并return
ans = Math.min(sum, ans);
return;
}
if (sum >= ans) {//如果还没有到达B楼,但是此时按按钮的次数sum已经大于等于ans,就说明此种走法不是最佳走法,return即可
return;
}
vis[start] = true;// 置为走过
if (start + arr[start] <= N && !vis[start + arr[start]]) {// 向上走,如果可以的话
dfs(start + arr[start], end, sum + 1);
}
if (start - arr[start] >= 1 && !vis[start - arr[start]]) {// 向下走,如果可以的话
dfs(start - arr[start], end, sum + 1);
}
//当该种走法完成后(可能行得通,也可能行不通),我们应该把该位置重新置为没访问过,供下一种走法使用
vis[start] = false;
}
}