【算法设计与分析】N皇后(回溯算法)

回溯VS递归

        很多人认为回溯和递归是一样的,其实不然。在回溯法中可以看到有递归的身影,但是两者是有区别的。

        回溯法从问题本身出发,在包含问题的所有可能解的解空间树中,从根结点出发,按照深度优先的策略进行搜索,对于解空间树的某个结点,若满足约束条件,则进入该子树继续搜索,否则将以该结点为根结点的子树进行剪枝,逐层向其祖先结点回溯,寻找可能实现的所有情况。和穷举法的思想相近,不同在于穷举法是将所有的情况都列举出来以后再一一筛选,而回溯法在列举过程如果发现当前情况根本不可能存在,就停止后续的所有工作,返回上一步进行新的尝试。

        递归从问题的结果出发,例如求 n!,要想知道 n!的结果,就需要知道 n*(n-1)! 的结果,而要想知道 (n-1)! 结果,就需要提前知道 (n-1)*(n-2)!。这样不断地向自己提问,不断地调用自己的思想就是递归。

        回溯和递归唯一的联系就是,回溯法可以用递归思想实现。


N皇后问题 
在n x n的棋盘上摆放n个皇后,而且n个皇后中的任意两个是不能处于同一行、同一列、或同一斜线上。

【分析】因为n皇后不能在同行,同列, 同斜线。

  1. 每一行放一个皇后,就解决了不在同行的问题。
  2. 在第i行的时候,遍历n列,试探位置。和之前所有行放的位置进行比较。
  3. 比较列:当前列 col 不等于之前所有列。 即col != arr[i] 。
  4. 比较斜线, 因为不再同一斜率为1或者-1的斜线。(row - i) / (col - arr[i]) != 1 或 -1
  5. 可以取巧用绝对值函数: abs(row-i) != abs(col-arr[i]) 。
     
public class NQueen {
    private int n;      // n个皇后
    private long sum;   // 可行解的数量
    private int[] arr;  // 当前的解

    public NQueen(int n){
        this.n = n;
        sum = 0;
        arr = new int[n+1];
    }
    
    // row col   i  arr[i]
    public boolean Check(int row, int col){
        // 每一行放一个,一定不在同一行
        for(int i = 1; i < row; i++){ 
            // 当前列是否与第一,二...列相同
        	// 当前点是否与第一,二...列斜率为正负1
            if(col == arr[i] || Math.abs(row - i) == Math.abs(col - arr[i])) 
                return false;
        }
        return true;
    }

    public void FindNQueen(int k) {
        if (k > n) {   //遍历到叶子节点,找出一种解, sum+1
            sum++;
            return;
        }
        for (int i = 1; i <= n; i++) {
            if (Check(k, i)) {   //检查是否满足条件
                arr[k] = i;      //记录
                FindNQueen(k + 1);   //递归查找
            }
        }
    }

    public static void main(String args[]){
    	System.out.println("请输入n的值:");
    	Scanner sc = new Scanner(System.in);
    	int n = sc.nextInt();
        NQueen nQueen = new NQueen(n);
        nQueen.FindNQueen(1);
        System.out.println(nQueen.sum);
    }
}

当N=8时,输出结果为92。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章