N-Queens II

描述

Follow up for N-Queens problem.

Now, instead outputting board configurations, return the total number of distinct solutions.

分析

只需要输出解的个数,不需要输出所有解,代码要比上一题简化很多。设一个全局计数器,每找到一个解就增1。

代码1

  1. // N-Queens II
  2. // 深搜+剪枝
  3. // 时间复杂度O(n!*n),空间复杂度O(n)
  4. public class Solution {
  5. public int totalNQueens(int n) {
  6. this.count = 0;
  7. int[] C = new int[n]; // C[i]表示第i行皇后所在的列编号
  8. dfs(C, 0);
  9. return this.count;
  10. }
  11. void dfs(int[] C, int row) {
  12. final int n = C.length;
  13. if (row == n) { // 终止条件,也是收敛条件,意味着找到了一个可行解
  14. ++this.count;
  15. return;
  16. }
  17. for (int j = 0; j < n; ++j) { // 扩展状态,一列一列的试
  18. final boolean ok = isValid(C, row, j);
  19. if (!ok) continue; // 剪枝:如果合法,继续递归
  20. // 执行扩展动作
  21. C[row] = j;
  22. dfs(C, row + 1);
  23. // 撤销动作
  24. // C[row] = -1;
  25. }
  26. }
  27. /**
  28. * 能否在 (row, col) 位置放一个皇后.
  29. *
  30. * @param C 棋局
  31. * @param row 当前正在处理的行,前面的行都已经放了皇后了
  32. * @param col 当前列
  33. * @return 能否放一个皇后
  34. */
  35. private static boolean isValid(int[] C, int row, int col) {
  36. for (int i = 0; i < row; ++i) {
  37. // 在同一列
  38. if (C[i] == col) return false;
  39. // 在同一对角线上
  40. if (Math.abs(i - row) == Math.abs(C[i] - col)) return false;
  41. }
  42. return true;
  43. }
  44. private int count; // 解的个数
  45. }

代码2

  1. // N-Queens II
  2. // 深搜+剪枝
  3. // 时间复杂度O(n!),空间复杂度O(n)
  4. public class Solution {
  5. public int totalNQueens(int n) {
  6. this.count = 0;
  7. this.columns = new boolean[n];
  8. this.main_diag = new boolean[2 * n - 1];
  9. this.anti_diag = new boolean[2 * n - 1];
  10. int[] C = new int[n]; // C[i]表示第i行皇后所在的列编号
  11. dfs(C, 0);
  12. return this.count;
  13. }
  14. void dfs(int[] C, int row) {
  15. final int N = C.length;
  16. if (row == N) { // 终止条件,也是收敛条件,意味着找到了一个可行解
  17. ++this.count;
  18. return;
  19. }
  20. for (int j = 0; j < N; ++j) { // 扩展状态,一列一列的试
  21. final boolean ok = !columns[j] &&
  22. !main_diag[row - j + N - 1] &&
  23. !anti_diag[row + j];
  24. if (!ok) continue; // 剪枝:如果合法,继续递归
  25. // 执行扩展动作
  26. C[row] = j;
  27. columns[j] = main_diag[row - j + N - 1] =
  28. anti_diag[row + j] = true;
  29. dfs(C, row + 1);
  30. // 撤销动作
  31. // C[row] = -1;
  32. columns[j] = main_diag[row - j + N - 1] =
  33. anti_diag[row + j] = false;
  34. }
  35. }
  36. private int count; // 解的个数
  37. // 这三个变量用于剪枝
  38. private boolean[] columns; // 表示已经放置的皇后占据了哪些列
  39. private boolean[] main_diag; // 占据了哪些主对角线
  40. private boolean[] anti_diag; // 占据了哪些副对角线
  41. public static void main(String[] args) {
  42. Solution s = new Solution();
  43. s.totalNQueens(1);
  44. }
  45. }

相关题目

原文: https://soulmachine.gitbooks.io/algorithm-essentials/content/java/dfs/n-queens-ii.html