深度优先搜索问题

时间:2014-06-11 13:18:01

标签: java algorithm graph-algorithm

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次移动。为什么会这样?

1 个答案:

答案 0 :(得分:0)

您的复制错误。您将a复制到b的行。您将每个b的值设置为a.get(i,j),其中a.get()不返回其值,但值%12除以3。

好的我发现,对于前6000次搜索(当你的堆栈溢出时),算法总是有一个有效的选择。

为防止您考虑广度优先搜索或设置最大搜索深度。

我添加了最大搜索深度并且算法返回,但是需要的转弯在不同的情况下从一个场景变为另一个场景。因此,有时需要200次移动,因此您无法设置任何较低值的最大搜索深度。但随后以200为最大搜索深度。即使存在更好的解决方案,任何200步骤解决方案都将被接受。

因此,我的建议是将深度优先搜索作为您的搜索算法。