将 N Queen 问题的所有解添加到数组列表中

Adding all solutions of N Queen Problem to an arrayList

提问人:Vivek Kumar 提问时间:9/15/2021 更新时间:9/15/2021 访问量:298

问:

n-queens 谜题是将 n 个皇后放在 (n×n) 棋盘上的问题,这样两个皇后就不能互相攻击。

我使用回溯来解决问题。但是我遇到了一个奇怪的问题。

下面是我写的代码:

import java.util.ArrayList;

public class NQueenProblem {

    static ArrayList<ArrayList<Integer>> ans = new ArrayList<ArrayList<Integer>>();

    static ArrayList<ArrayList<Integer>> nQueen(int n) {

        ArrayList<Integer> positions = new ArrayList<Integer>();
        //boolean[][] placed = new boolean[n][n];
        solveNQueenRec(n, 0, new boolean[n][n], positions);
        //for dubugging purpose. This prints empty arrays. not able to understand why?
        for (ArrayList<Integer> list : ans)
            System.out.println(list);
        return ans;
    }

    static void solveNQueenRec(int n, int col, boolean[][] placed, ArrayList<Integer> positions) {
        if (col == n) {
            //for debugging process
            System.out.println("Adding " + positions);
            ans.add(positions);
            System.out.println("Added " + positions);
        }
        for (int row = 0; row < n && col < n; row++) {
            if (isSafe(row, col, placed, n)) {
                placed[row][col] = true;
                positions.add(row + 1);
                solveNQueenRec(n, col + 1, placed, positions);
                placed[row][col] = false;
                positions.remove(positions.size() - 1);
            }
        }
        // return null;
    }

    private static boolean isSafe(int row, int col, boolean[][] placed, int n) {
        boolean safe = true;
        // checking if exists in same row
        for (int i = 0; i < col; i++) {
            if (placed[row][i])
                safe = false;
        }
        // checking for upper diagonal
        for (int i = row, j = col; i >= 0 && j >= 0; i--, j--) {
            if (placed[i][j])
                safe = false;
        }
        // checking for lower diagonal
        for (int i = row, j = col; i < n && j >= 0; i++, j--) {
            if (placed[i][j])
                safe = false;
        }
        return safe;
    }

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        nQueen(4);

    }

}

我无法理解的是,当我在日志列表中看到被添加到我的 ans 时,为什么我的 ans 是空的。 我是在犯什么愚蠢的错误。请帮我解决这个问题。如果可能的话,请帮助我提供链接以了解该问题以及我将来如何避免这些问题。

Java 算法 Pass-by-Reference 回溯 传递

评论

1赞 tgdavies 9/15/2021
每次添加一个项目时,您也会删除一个项目,因此它最终为空,如您的 println 所示。positions

答:

-1赞 chanrlc 9/15/2021 #1

添加此检查,确保它大于零,然后打印出答案。此外,添加打印女王功能,您将清楚地看到答案。如果这解决了您的问题,请作为答案。

for (ArrayList<Integer> list : ans) {
    if (list.size() > 0)
        System.out.println(list);
}

static void solveNQueenRec(int n, int col, boolean[][] placed, ArrayList<Integer> positions) {
    if (col == n) 
        printQueens(positions);
    
    for (int row = 0; row < n && col < n; row++) {
        if (isSafe(row, col, placed, n)) {
            placed[row][col] = true;
            positions.add(row + 1);
            solveNQueenRec(n, col + 1, placed, positions);
            placed[row][col] = false;
            positions.remove(positions.size() - 1);
        }
    }
    // return null;
}


public static void printQueens(ArrayList<Integer> q) {
    int n = q.size();
    for (int i = 0; i < n; i++) {
        for (int j = 1; j <= n; j++) {
            if (q.get(i) == j) 
                System.out.print("Q ");
            else           
                System.out.print("* ");
        }
        System.out.println();
    }  
    System.out.println();
}

solution to 4-queens sample:
* Q * * 
* * * Q 
Q * * * 
* * Q * 

* * Q * 
Q * * * 
* * * Q 
* Q * *

评论

0赞 tgdavies 9/15/2021
这根本不是OP的问题。
0赞 chanrlc 9/15/2021
修改代码后,答案将是正确的: 添加 [2, 4, 1, 3] 添加 [2, 4, 1, 3] 添加 [3, 1, 4, 2] 添加 [3, 1, 4, 2]
0赞 tgdavies 9/15/2021
“我无法理解的是,当我在日志列表中看到被添加到我的 ans 中时,为什么我的 ans 是空的” 这是 OPs 问题,您还没有回答。
0赞 chanrlc 9/15/2021
因为没有打印出来的解决方案。
0赞 chanrlc 9/15/2021
尝试在黑板上打印皇后。不要添加到 ans 列表。由于 4-queens 只有两个解决方案,并且列表大小为 4,因此将返回两个空列表 []。我清楚吗?
2赞 tgdavies 9/15/2021 #2

我想你相信当 JVM 执行时

   ans.add(positions);

它正在获取当前状态的副本并将其添加到列表中。它不是,它正在做代码所说的:添加对 .positionsArrayListans

中的所有项目都是对相同的引用,并且当您打印出来时,该数组列表是空的。ansArrayListans

1赞 Jean-Baptiste Yunès 9/15/2021 #3
ans.add(positions);

是你的“问题”。您只是添加到对列表的引用中。因此充满了对同一列表的引用。当您在插入后多次修改时,直到清空它,最后充满了 n 个引用(n 是找到的解决方案的数量)与末尾为空的相同列表。anspositionsanspositionspositionsanspositions

您需要在找到解决方案时插入当前列表的副本:positions

ans.add(new ArrayList<Integer>(positions));

副本是通过构建具有原始列表确切内容的新列表来获得的。