http://usacotraining.blogspot.com/2013/10/problem-142-clocks.html 我正在尝试使用Depth First Search来解决此问题。我创建了一个基于3x3阵列的Node类,并使用了大小为4 ^ 9的被访问数组。然而,这显然根本不起作用(它不打印任何东西)。我的调试尝试(见评论)告诉我,由于某些原因,阵列似乎每次都在重置,但我无法弄清楚原因。
另外,我确信我的代码不必要地复杂,并且有更好的方法来执行这样的DFS。有人能告诉我一个更好的方法吗?
/*
ID: akshajk1
LANG: JAVA
TASK: clocks
*/
import java.util.*;
import java.io.*;
import java.lang.*;
import java.math.*;
class clocks {
public static boolean[] visited;
public static boolean done;
public static String[] moves = {"ABDE", "ABC", "BCEF", "ADG", "BDEFH", "CFI", "DEGH", "GHI", "EFHI"};
public static Stack<Integer> ans = new Stack<Integer>();
public static Stack<Integer> finalans = new Stack<Integer>();
public static void main(String[] args) throws Exception {
BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
// BufferedReader bf = new BufferedReader(new FileReader("clocks.in"));
// PrintWriter out = new PrintWriter(new FileWriter("clocks.out"));
// int n = Integer.parseInt(bf.readLine());
int[][] a = new int[3][3];
for(int i=0; i<3; i++) {
StringTokenizer st = new StringTokenizer(bf.readLine());
for(int j=0; j<3; j++) a[i][j] = Integer.parseInt(st.nextToken());
}
visited = new boolean[4*4*4*4*4*4*4*4*4];
Node x = new Node(a);
dfs(x);
for(int i : finalans)
out.println(i + " ");
out.close(); System.exit(0);
}
public static void dfs(Node a) {
if(done) return;
int n = 0;
for(int i=0; i<3; i++)
for(int j=0; j<3; j++)
n = 4*n+a.get(i, j);
if(visited[n]) return;
// for(int i=0; i<3; i++) { for(int j=0; j<3; j++) System.out.print(a.get(i, j)); System.out.print("\n"); } System.out.print("\n");
// System.out.println(Arrays.toString(ans.toArray()) + "\n");
boolean gotit = true;
for(int i=0; i<3; i++) for(int j=0; j<3; j++) if(a.get(i, j) != 0) gotit = false;
if(gotit) {
for(int i : ans)
finalans.push(i);
done = true;
return;
}
visited[n] = true;
for(int i=0; i<moves.length; i++) {
char[] x = moves[i].toCharArray();
int[][] b = new int[3][3];
for(int k=0; k<3; k++)
for(int kk=0; kk<3; kk++)
b[k][kk] = a.get(k, kk);
Node abc = new Node(b);
for(char c : x)
abc = abc.turn(c);
ans.push((i+1));
dfs(abc);
}
ans.pop();
}
}
class Node {
final private int[][] a;
public Node(int[][] aaa) {
a = new int[3][3];
for(int i=0; i<3; i++)
for(int j=0; j<3; j++)
a[i][j] = aaa[i][j];
}
public int get(int i, int j) {
return (a[i][j] % 12)/3;
}
public Node turn(char c) {
int val = c - 'A';
int[][] b = new int[3][3];
for(int i=0; i<3; i++)
for(int j=0; j<3; j++)
b[i][j] = a[i][j];
b[val/3][val%3] += 3;
if(b[val/3][val%3] > 12) b[val/3][val%3] %= 12;
if(b[val/3][val%3] == 0) b[val/3][val%3] += 12;
Node ansans = new Node(b);
for(int i=0; i<3; i++) { for(int j=0; j<3; j++) System.out.print(ansans.get(i, j)); System.out.print("\n"); } System.out.print("\n");
return ansans;
}
}
编辑:感谢您的帮助!我能够纠正复制错误,现在打印语句更有意义,但程序仍然在执行四次移动后停止。我更改了被访问数组以将初始值标记为true,从而得到以下代码:
import java.util.*;
import java.io.*;
import java.lang.*;
import java.math.*;
class clocks {
public static boolean[] visited;
public static boolean done;
public static String[] moves = {"ABDE", "ABC", "BCEF", "ADG", "BDEFH", "CFI", "DEGH", "GHI", "EFHI"};
public static Stack<Integer> ans = new Stack<Integer>();
public static Stack<Integer> finalans = new Stack<Integer>();
public static void main(String[] args) throws Exception {
BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
// BufferedReader bf = new BufferedReader(new FileReader("clocks.in"));
// PrintWriter out = new PrintWriter(new FileWriter("clocks.out"));
// int n = Integer.parseInt(bf.readLine());
int[][] a = new int[3][3];
for(int i=0; i<3; i++) {
StringTokenizer st = new StringTokenizer(bf.readLine());
for(int j=0; j<3; j++) a[i][j] = Integer.parseInt(st.nextToken());
}
visited = new boolean[4*4*4*4*4*4*4*4*4];
Node x = new Node(a);
int n = 0;
for(int xx=0; xx<3; xx++)
for(int j=0; j<3; j++)
n = 4*n+x.get(xx, j);
visited[n] = true;
dfs(x);
for(int i : finalans)
out.println(i + " ");
out.close(); System.exit(0);
}
public static void dfs(Node a) {
if(done) return;
// for(int i=0; i<3; i++) { for(int j=0; j<3; j++) System.out.print(a.get(i, j)); System.out.print("\n"); } System.out.print("\n");
// System.out.println(Arrays.toString(ans.toArray()) + "\n");
boolean gotit = true;
for(int i=0; i<3; i++) for(int j=0; j<3; j++) if(a.get(i, j) != 0) gotit = false;
if(gotit) {
for(int i : ans)
finalans.push(i);
done = true;
return;
}
for(int i=0; i<moves.length; i++) {
char[] x = moves[i].toCharArray();
int[][] b = new int[3][3];
for(int k=0; k<3; k++) {
for(int kk=0; kk<3; kk++) {
b[k][kk] = a.get(k, kk)*3;
if(b[k][kk] == 0) b[k][kk] = 12;
}
}
Node abc = new Node(b);
for(char c : x)
abc = abc.turn(c);
int n = 0;
for(int xx=0; xx<3; xx++)
for(int j=0; j<3; j++)
n = 4*n+abc.get(xx, j);
if(!visited[n]) {
visited[n] = true;
ans.push((i+1));
dfs(abc);
ans.pop();
}
}
}
}
class Node {
final private int[][] a;
public Node(int[][] aaa) {
a = new int[3][3];
for(int i=0; i<3; i++)
for(int j=0; j<3; j++)
a[i][j] = aaa[i][j];
}
public int get(int i, int j) {
return (a[i][j] % 12)/3;
}
public Node turn(char c) {
int val = c - 'A';
int[][] b = new int[3][3];
for(int i=0; i<3; i++)
for(int j=0; j<3; j++)
b[i][j] = a[i][j];
b[val/3][val%3] += 3;
if(b[val/3][val%3] > 12) b[val/3][val%3] %= 12;
if(b[val/3][val%3] == 0) b[val/3][val%3] += 12;
Node ansans = new Node(b);
// for(int i=0; i<3; i++) { for(int j=0; j<3; j++) System.out.print(ansans.get(i, j)); System.out.print("\n"); } System.out.print("\n");
return ansans;
}
}
(我还修复了另一个错误)。由于某种原因,这仍然无法正常工作,并且会产生堆栈溢出错误。我知道有很多递归,但最多只能进行9 * 3 = 27次移动。为什么会这样?
答案 0 :(得分:0)
您的复制错误。您将a复制到b的行。您将每个b的值设置为a.get(i,j),其中a.get()不返回其值,但值%12除以3。
好的我发现,对于前6000次搜索(当你的堆栈溢出时),算法总是有一个有效的选择。
为防止您考虑广度优先搜索或设置最大搜索深度。
我添加了最大搜索深度并且算法返回,但是需要的转弯在不同的情况下从一个场景变为另一个场景。因此,有时需要200次移动,因此您无法设置任何较低值的最大搜索深度。但随后以200为最大搜索深度。即使存在更好的解决方案,任何200步骤解决方案都将被接受。
因此,我的建议是将深度优先搜索作为您的搜索算法。