网易的游历魔法王国,考虑往回走的情况。暴力深搜代码。
import java.util.Scanner;
/**
* 网易游历魔法王国问题,考虑往回走的情况。
* 此处使用深度优先搜索,抛砖引玉,希望有大神给最优算法代码。
*/
public class Test10 {
static int sum = 0;
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int N = in.nextInt();
int L = in.nextInt();
in.nextLine();
int[] parent = new int[N - 1];
for (int i = 0; i < N - 1; i++) {
parent[i] = in.nextInt();
}
in.nextLine();
sum = 0;
int[] mark = new int[N]; // 用于表示是否被访问过
try {
work1(parent, 0, 0, -1, mark, L + 1, N);
} finally {
System.out.println(sum);
}
in.close();
}
/**
* 深度优先搜索,可以走重复的路径,直到步数用完。
*
* @param parent 输入的数组,表示相邻边
* @param temp 暂存游历的城市数目
* @param id 表示当前游历到的城市
* @param preid 表示前面一个游历的城市
* @param mark 标志数组,记录游历了哪些城市
* @param L 表示剩余的步数
* @param N 表示总的城市个数
* @return 返回剩余步数
*/
public static int work1(int[] parent, int temp, int id, int preid, int[] mark, int L, int N) {
// 第0个节点假设它的前一个节点为-1;
if (id == -1)
return L;
L--; // 游历步数-1
// 如果城市没有被访问过,则游历城市数+1;
if (mark[id] == 0 && ++temp > sum)
sum = temp;
mark[id]++; // 标记已经访问此城市。
// 如果没有游历次数了,则退出。
if (L == 0) {
mark[id]--; // 回溯;
return 0;
}
// 如果所有的城市都游历过了,但是步数还没有用完,则应该直接退出代码,最大值即为城市个数。防止步数特别大的情况。
int count = 0;
for (int i = 0; i < N; i++) {
if (mark[i] == 0) {
break;
}
count++;
}
if (count == N) {
sum = N;
new Exception(); // 用异常退出递归
}
// 找出接下来可以访问的城市,继续走
for (int i = 0; i < N - 1; i++) {
if (parent[i] == id && mark[i + 1] == 0) // 如果下一个城市没有被访问过,则往下走。
{
int leftL = work1(parent, temp, i + 1, id, mark, L, N);
if (leftL > 0) // 如果一直往下走到尽头后还有剩余的步骤,则往回走。
work1(parent, temp, preid, id, mark, leftL, N);
}
}
// 直接往回走,不往下走了,找其他支路上的没访问过的节点。
int left = work1(parent, temp, preid, id, mark, L, N);
// 回溯。
mark[id]--;
return left;
}
} 5 2
0 1 2 3
3
6 7
0 1 2 0 2 4
6
