起初,我考虑使用暴力算法,并在下面留下了它的代码,但事实证明搜索所有答案比生成所有配置并测试有效答案更加简单。这是搜索代码,最终看起来非常像@Brent Washburne的代码。在我的笔记本上运行时间为53毫秒。
import java.util.Arrays;
class Puzzle {
final int path[][];
final int grid[] = new int[25];
Puzzle(int[][] path) {
this.path = Arrays.asList(path).stream().map(pair -> {
return new int[] { pair[0] - 1, pair[1] - 1 };
}).toArray(int[][]::new);
}
void print() {
System.out.println();
for (int i = 0; i < grid.length; i += 5)
System.out.println(
Arrays.toString(Arrays.copyOfRange(grid, i, i + 5)));
}
void findPaths(int ip, int i) {
if (grid[i] != -1) return;
grid[i] = ip;
if(i == path[ip][1])
if (ip < path.length - 1) findPaths(ip + 1, path[ip + 1][0]);
else print();
else {
if (i < 20) findPaths(ip, i + 5);
if (i > 4) findPaths(ip, i - 5);
if (i % 5 < 4) findPaths(ip, i + 1);
if (i % 5 > 0) findPaths(ip, i - 1);
}
grid[i] = -1;
}
void solve() {
Arrays.fill(grid, -1);
findPaths(0, path[0][0]);
}
public static void main(String[] args) {
new Puzzle(new int[][]{{1, 22}, {4, 17}, {5, 18}, {9, 13}, {20, 23}}).solve();
}
}
旧的、不好的答案
如果你反向思考,将所有的网格方块分配到路径上并测试分配是否有效,这个问题就可以通过暴力方法解决。总共有25个网格方块,需要构建5条路径,每条路径有2个端点。因此,你知道这10个点所在的路径。剩下的15个方块只需标记它们所在的路径即可。每个方块有5种可能性,因此总共有5^15种情况。这大约是300亿。接下来要做的就是构建一个高效的检查器,判断给定的分配是否为一组5条有效路径。这可以通过线性时间搜索轻松完成。下面的代码可以在我的 MacBook 上大约2分钟内找到你的解决方案,并在不到11分钟的时间内进行全面测试:
import java.util.Arrays;
public class Hacking {
static class Puzzle {
final int path[][];
final int grid[] = new int[25];
Puzzle(int[][] path) { this.path = path; }
void print() {
System.out.println();
for (int i = 0; i < grid.length; i += 5)
System.out.println(
Arrays.toString(Arrays.copyOfRange(grid, i, i + 5)));
}
boolean trace(int p, int i, int goal) {
if (grid[i] != p) return false;
grid[i] = -1;
boolean rtn =
i == goal ? !Arrays.asList(grid).contains(p) : nsew(p, i, goal);
grid[i] = p;
return rtn;
}
boolean nsew(int p, int i, int goal) {
if (i < 20 && trace(p, i + 5, goal)) return true;
if (i > 4 && trace(p, i - 5, goal)) return true;
if (i % 5 < 4 && trace(p, i + 1, goal)) return true;
if (i % 5 > 0 && trace(p, i - 1, goal)) return true;
return false;
}
void test() {
for (int ip = 0; ip < path.length; ip++)
if (!trace(ip, path[ip][0] - 1, path[ip][1] - 1)) return;
print();
}
void enumerate(int i) {
if (i == grid.length) test();
else if (grid[i] != -1) enumerate(i + 1);
else {
for (int ip = 0; ip < 5; ip++) {
grid[i] = ip;
enumerate(i + 1);
}
grid[i] = -1;
}
}
void solve() {
Arrays.fill(grid, -1);
for (int ip = 0; ip < path.length; ip++)
grid[path[ip][0] - 1] = grid[path[ip][1] - 1] = ip;
enumerate(0);
}
}
public static void main(String[] args) {
new Puzzle(new int[][]{{1, 22}, {4, 17}, {5, 18}, {9, 13}, {20, 23}}).solve();
}
}
起始数组:
[ 0, -1, -1, 1, 2]
[-1, -1, -1, 3, -1]
[-1, -1, 3, -1, -1]
[-1, 1, 2, -1, 4]
[-1, 0, 4, -1, -1]
结果:
[ 0, 1, 1, 1, 2]
[ 0, 1, 3, 3, 2]
[ 0, 1, 3, 2, 2]
[ 0, 1, 2, 2, 4]
[ 0, 0, 4, 4, 4]