N皇后(N Queens)这样的全排列类型的DFS问题怎么在找到第一个解的时候就不再继续下去?

突然想到这个问题。。 比如常规的N皇后问题,指定皇后个数n,遍历所有的解的可能性然后打印出所有的解,方法是用for循环里面调用递归: ... priv…
关注者
4
被浏览
1,110
登录后你可以
不限量看优质回答私信答主深度交流精彩内容一键收藏

给DFS增加一个终止条件(Terminator)就好了。

最近稍微研究了一下DFS,也问了一些人,题其实跟之前想的一样,就是增加一个终止条件让递归停下来。不过俗话说「人理解迭代,神理解递归」,我一开始无法理解增加一个终止条件会产生什么效果,比如会有「明明已经有了一个return了(在找到答案的时候),为什么还要增加一个return」这样的疑惑。

N Queens这样的for循环里的DFS可以用一个N * N的矩阵来模拟过程(类似的还有Combination Sum(39. Combination Sum ),Sudoku Solver等问题)。我简单画个图:


跟覃超上课提到的类似,递归(dfs)有点像《盗梦空间》,会有一层层的梦,梦醒来的时候会从内层往外层按照stack的顺序醒来。所以,途中找到一个答案之后,for循环移动到下一个格子发现不满足了,就回到上一层的梦。然后上一层再用for循环把皇后一次次右移。所以,如果我们增加一个terminator,在找到一个解之后就会不断地从底层的梦中醒来,不再执行下去。所以只要判断当前解集是否大于0就行了。

    public void dfs(List<List<String>> result, int row, int n, int[] col) {
        if (row == n) {
            List<String> cell = new ArrayList<>();
//打印一个解
            for (int i = 0; i < row; i++) {
                StringBuilder sb = new StringBuilder();
                for (int j = 0; j < row; j++) {
                    if (col[i] == j) {
                        sb.append("Q");
                    } else {
                        sb.append(".");
                    }
                }
                cell.add(sb.toString());
            }
            result.add(new ArrayList<String>(cell));
            return;
        }
        if (result.size() > 0) return;
        for (int i = 0; i < n; i++) {
            //i表示Q所在的列 从头到尾遍历一遍
            col[row] = i;
            if (checkValid(row, col)) {
                dfs(result, row + 1, n, col);
            }
        }
    }

@LoveYayoi 的想法也是类似的,就是给dfs一个返回值类型。如下:

    public boolean dfs(List<List<String>> result, int row, int n, int[] col) {
        if (row == n) {
            List<String> cell = new ArrayList<>();
//打印一个解
            for (int i = 0; i < row; i++) {
                StringBuilder sb = new StringBuilder();
                for (int j = 0; j < row; j++) {
                    if (col[i] == j) {
                        sb.append("Q");
                    } else {
                        sb.append(".");
                    }
                }
                cell.add(sb.toString());
            }
            result.add(new ArrayList<String>(cell));
            return true;
        }
        for (int i = 0; i < n; i++) {
            col[row] = i;
            if (checkValid(row, col)) {
                if (dfs(result, row + 1, n, col)) return true;
            }
        }
        return false;
    }

更详细的分析可以看我的blog: 52. N-Queens II ,全排列类型DFS的理解

知乎的编辑器好难用哦。。烦 。能用markdown吗

-