【问题标题】:Parallel Sudoku Solver in JavaJava中的并行数独求解器
【发布时间】:2016-12-25 14:49:06
【问题描述】:

我有一个作业需要在 Java 中实现数独求解器的顺序和并行版本(使用 ForkJoin 框架进行并行处理)。

我写了顺序的,它工作正常。算法思想是一个简单的回溯练习:对于每个尚未填充的单元格(从表格的左上角开始),用所有合法候选人(从 1 到 9 的整数),直到您到达矩阵的末尾(第 9 行第 9 行)。如果您已到达终点,则增加解决方案编号。

我想实现并行版本,只是为为特定单元格找到的每个有效候选者生成一个新线程,然后等待它们。它似乎不起作用,我无法找到原因。

我发布了应该完成整个工作的课程,希望能找到一个好的建议:

class SolveSudoku extends RecursiveAction{
    private int i, j;
    private int[][] cells;

    SolveSudoku(int i, int j, int[][] cells){
        this.i = i;
        this.j = j;
        this.cells = cells;
    }

    @Override
    protected  void compute(){
        if (j == 9) {
            j = 0;
            if (++i == 9){
                solutions++;
                System.out.println(solutions);
                return;
            }
        }

        if (cells[i][j] != 0 ){                             // skip filled cells
            SolveSudoku s =  new SolveSudoku(i, j+1, cells);
            s.compute();
            return;
        }


        ArrayList<Integer> vals = new ArrayList<Integer>();
        for (int val = 1; val <= 9; val++)                 // try all the legal candidates for i, j
            if (legal(i,j,val,cells))
                vals.add(val);


        if(vals.size() == 1){                            // only one, no new threads
            cells[i][j] = vals.get(0);
            new SolveSudoku(i, j+1, cells).compute();
        }
        else{
            SolveSudoku threads[] = new SolveSudoku[vals.size()];
            int n = 0;
            int first;
            for(int k=0; k<vals.size(); k++){
                if(k == vals.size()-1){
                    cells[i][j] = vals.get(k);
                    threads[n] = new SolveSudoku(i, j+1, cells);
                    threads[n].compute();
                }
                else{
                    cells[i][j] = vals.get(k);
                    threads[n] = new SolveSudoku(i, j+1, cells);
                    threads[n].fork();
                }
                n++;
            }


            for(int k=0; k<threads.length-1; k++)
                if(k != vals.size()-1)
                    threads[k].join();

        }

        cells[i][j] = 0;
        return;
    }}

new ForkJoinPool().invoke(new SolveSudoku(0, 0, M)); // where *M* is a sudoku instance to solve where all the unfilled cells contain '0'

【问题讨论】:

  • 那么并行算法应该一次性解决整个数独问题?
  • 是的,@vatbub!事实上,如果你定义了一个经典的 main 方法(在类定义之外的行),并且如果你在下面添加行 threads[n].join(); else 块的最后一行(在 for 循环中),一切正常。不知道错误在哪里,但似乎线程做了他们想做的事......

标签: java parallel-processing sudoku fork-join forkjoinpool


【解决方案1】:

首先,您应该考虑如果一个线程完成它的工作会发生什么。您应该注意到它试图将单元格重置为 0,但是如果有另一个子线程在使用该单元格怎么办?

显然,如果另一个线程访问同一个 Cell 试图检查它是否合法,它可能必须输入错误的值,因为另一个线程将零放回其中!

【讨论】:

  • 这个答案提出了一个很好的观点,但作为评论会更好,因为它不是问题的解决方案。
  • 很遗憾,我认为你说得不对。由于“boss”线程等待它产生的每个子线程,因此在“boss”终止后,没有子线程(它或其子线程)可以执行。而且,由于我为找到的每个新的合法候选人创建一个新实例,对象(cells 字段)不会在线程之间共享,因此我们不需要任何同步。
  • 如果孩子还没有,b0ss如何终止?问题是,还有其他子线程同时访问同一个网格,修改它。可悲的是,这不是价值调用,而是参考。
【解决方案2】:

我认为您应该将数组的 副本 传递给新线程。在您的代码中,您将相同的数组传递给所有线程,它们会尝试同时插入正确的值。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-02-21
    • 1970-01-01
    • 2014-06-06
    • 1970-01-01
    • 2011-05-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多