回溯法解决八皇后问题

在一个8x8的棋盘上每个皇后的行上,列上,主次对角线上都不允许出现其他的皇后。
很显然安放皇后需要逐行或者逐列的安放并进行判断,回溯法就是在判断不成功时回溯到上一行或者上一列,直到判断成功。

在梁勇书上关于8皇后问题的回溯法算法如下

private boolean search(){
		int k = 0;
	while(k >= 0 &&  k < SIZE){
		int j = findPosition(k); //找到该行可行的列
		if(j < 0) {
			queens[k] = -1;
			k--;//不行的时候就回溯
		} else {
			queens[k] = j;
			k++;
	}
}
if(k == -1)
	return false;
else
	return true;
}
public int findPosition(int k){
	int start = queens[k] + 1; //每次进行回溯的时候从上一次列数加一的地方开始遍历,避免死循环
	for(int j = start; j < SIZE; j ++){
	if(isValid(k , j)) //isValid是判断皇后所放位置是否可行的方法,返回boolean型参数
	return j;
	}
return -1;
}

很显然上面的方法只能找到一种解法。并不能找到所有的解法。
如果要用回溯法找到所有的解法呢?很显然需要在找到一个解法后能够继续找,并将这个解法储存下来。
递归加回溯的算法能够很好的解决。
在leetCode上有关于这题的解法。说实话,递归难理解,也难运用。看到这个解法时候我只能理解递归结果,实在不知道如何将递归这种解法运用于其他题目中。也许多做以后,我能慢慢运用起来吧

 int rows[];
  // "hill" diagonals
  int hills[];
  // "dale" diagonals
  int dales[];
  int n;
  int queens[];
List<List<String>> output = new ArrayList();

 
//下面这段回溯法,就是关键的递归算法,说实话这段代码第一次让我感觉到什么叫做简洁高效
  public void backtrack(int row) {//row指代行数
    for (int col = 0; col < n; col++) {//col指代列数
      if (isNotUnderAttack(row, col)) {//isNotUnderAttack就是判断这个皇后摆放位置是否可行
        placeQueen(row, col);//可以的话,就将该皇后位置保存
        // if n queens are already placed
        if (row + 1 == n) addSolution();//addSolution 如果可以运行到最后一行皇后将结
        //果打印出来并储存在output中
          // if not proceed to place the rest
        else backtrack(row + 1);//在运行到最后一个之前,就递归直到找到最后一行
        // backtrack
        removeQueen(row, col);/*如果递归到某一行列时不可行或得到了结果,那么这个方法就会在不可行或者得到结果的时候将此时这个皇后储存的该行该列删去,并从该行的下一列继续运行,再结合前面的递归,也就可以遍历到整个行列了。
      }
    }
  }

 

下面贴出LeetCode的完整解法解法
注意判断可行的思路是两个皇后之间不能同行同列也不能在同一根主次对角线上,换句话说,行列号不能相等,行列的差与和也不能相等

class Solution {
  int rows[];
  // "hill" diagonals
  int hills[]; 
  // "dale" diagonals
  int dales[];
  int n;
  // output
  List<List<String>> output = new ArrayList();
  // queens positions
  int queens[];

  public boolean isNotUnderAttack(int row, int col) {
    int res = rows[col] + hills[row - col + 2 * n] + dales[row + col];
    return (res == 0) ? true : false;
  }

  public void placeQueen(int row, int col) {
    queens[row] = col;
    rows[col] = 1;
    hills[row - col + 2 * n] = 1;  // "hill" diagonals
    dales[row + col] = 1;   //"dale" diagonals
  }

  public void removeQueen(int row, int col) {
    queens[row] = 0;
    rows[col] = 0;
    hills[row - col + 2 * n] = 0;
    dales[row + col] = 0;
  }

  public void addSolution() {
    List<String> solution = new ArrayList<String>();
    for (int i = 0; i < n; ++i) {
      int col = queens[i];
      StringBuilder sb = new StringBuilder();
      for(int j = 0; j < col; ++j) sb.append(".");
      sb.append("Q");
      for(int j = 0; j < n - col - 1; ++j) sb.append(".");
      solution.add(sb.toString());
    }
    output.add(solution);
  }

  public void backtrack(int row) {
    for (int col = 0; col < n; col++) {
      if (isNotUnderAttack(row, col)) {
        placeQueen(row, col);
        // if n queens are already placed
        if (row + 1 == n) addSolution();
          // if not proceed to place the rest
        else backtrack(row + 1);
        // backtrack
        removeQueen(row, col);
      }
    }
  }

  public List<List<String>> solveNQueens(int n) {
    this.n = n;
    rows = new int[n];
    hills = new int[4 * n - 1];
    dales = new int[2 * n - 1];
    queens = new int[n];

    backtrack(0);
    return output;
  }
}

作者:LeetCode
链接:https://leetcode-cn.com/problems/n-queens/solution/nhuang-hou-by-leetcode/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值