【问题标题】:My method should be iterating many many times but it isn't, why?我的方法应该迭代很多次,但它不是,为什么?
【发布时间】:2013-12-23 08:20:44
【问题描述】:

我正在编写一个数独求解算法,并且我正在尝试实现一种演绎方法来解决这个难题。但是我必须对递归或其他东西有一个松散的把握,因为我的算法似乎最多只改变一次电路板,即使我设置的条件应该在大多数情况下返回 true。这是我的方法

public void CRME() {
    for (Node n : cells) {
        scanColumn(n);
        scanRow(n);
        scanMiniGrid(n);
        sortBoardVals();
    }
}

这会扫描每一列、每一行和每一个小网格,并在代表棋盘的数组列表中剔除每个节点的可能值。

    public void solve(){
    boolean canChange = false;
    ArrayList<Node> before = new ArrayList<Node>(cells);
    CRME();
    for(Node n : cells){
        int i = cells.indexOf(n);
        if(n.isEqual(before.get(i))){
            canChange = false;
        } else {
            canChange = true;
            break;
        }

    }
    if(canChange){
        System.out.println("Solving...");
        solve();
    }
}

这是一个求解算法,它应该自我调用,直到它完全耗尽。

这是我的节点类

public class Node {
public ArrayList<Integer> posVals = new ArrayList<Integer>(9) {{
    add(1);
    add(2);
    add(3);
    add(4);
    add(5);
    add(6);
    add(7);
    add(8);
    add(9);
}};
private int ROW_ID;
private int COL_ID;
private int MG_ID;
static boolean hasChanged = true;

int value = 0;

public boolean isEqual(Node n){
    if(this.posVals.size() == n.posVals.size()){
        return true;
    }
    else return false;
}
}

我可能正在考虑重新考虑我的项目,因为我认为使用数组列表会使问题复杂化。

CRME 中的方法基本上是扫描每个节点并找到包含在相同 Column Row 和 MiniGrid 中的每个节点的值,并将它们从节点的可能值数组列表中删除。

排序板值方法然后检查节点中的数组列表的大小是否为 1,如果是,则将该节点的值设置为 Arraylist 中的最后一个值。

    public void sortBoardVals() {
    for (Node n : cells) {
        if (n.posVals.size() == 1) {
            if (n.value == 0)
                n.value = n.posVals.get(0);
        }
    }
}

public void scanColumn(Node n) {
    for (Node node : cells) {
        ArrayList<Integer> toRemove = new ArrayList<Integer>();
        if (node.get_COL_ID() == n.get_COL_ID()) {
            toRemove.add(node.getValue());
        }

        n.posVals.removeAll(toRemove);

    }

}

public void scanRow(Node n) {
    for (Node node : cells) {
        ArrayList<Integer> toRemove = new ArrayList<Integer>();
        if (node.get_ROW_ID() == n.get_ROW_ID()) {
            toRemove.add(node.getValue());
        }

        n.posVals.removeAll(toRemove);

    }
}

public void scanMiniGrid(Node n) {
    for (Node node : cells) {
        ArrayList<Integer> toRemove = new ArrayList<Integer>();
        if (node.get_MG_ID() == n.get_MG_ID()) {
            toRemove.add(node.getValue());
        }
        n.posVals.removeAll(toRemove);
    }
}

【问题讨论】:

  • 因为节点数是恒定的,所以应该使用 Node[] 而不是 ArrayList。同样,您应该使用 boolean[] 而不是 ArrayList 来表示可能的值(对于每个值,true = 可能,false = 不可能)
  • 没想到那样,看来我得彻底重新考虑数据结构了,谢谢。
  • @Saposhiente 那是非常小的东西。我看不出这些更改中的任何一个会如何使这变得更容易。
  • @JohnKugelman 这不是一个解决方案,但它可以提高效率。这就是为什么我将其发布为评论,而不是答案。

标签: java recursion methods arraylist sudoku


【解决方案1】:

在第二个窗格中,看起来您复制了一个单元格并将其命名为“之前”。

然后您正在比较单元格和之前的项目,因此在不知道 CRME 中的功能做什么的情况下,简单的答案似乎是单元格和之前的项目是相等的。

我也不知道您是如何设置实际拼图的。您确实意识到,对于大多数未解决的数独中的大量单元格,其值不会受到限制,对吧?

我会首先设置一个除了一个单元格之外的完整谜题,然后在调试器尝试解决该单元格时跟踪您的代码。

HTH!

【讨论】:

  • 谢谢,如果我也给他们看会更清楚,现在是凌晨 5 点,我很累哈哈
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-15
  • 1970-01-01
  • 2020-11-07
  • 1970-01-01
  • 2020-08-23
  • 1970-01-01
相关资源
最近更新 更多