2018-08-10

回溯法之n后问题

问题描述

在n x n格的棋盘上放置彼此不受攻击的n个皇后。按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线的棋子。n后问题等价于n x n格的棋盘上放置n个皇后,任何2个皇后不放在同一行或同一列或同一斜线上。

算法设计

用n元组x[1:n]表示n后问题的解,其中x[i]表示皇后放在棋盘的第i行的第x[i]列。由于不允许将2个皇后放在同一列上。所以解向量中的x[i]互不相同。2个皇后不能放在同一斜线上是问题的隐约束。对于一般的n后问题,这一隐约束条件可以化成显约束的形式。如果将n x n格的棋盘看做二维方针,其行号从上到下,列号从左到右依次编号为1,2,...,n,从棋盘左上角到右下角的主对角线及其平行线(即斜率为-1的各斜线)上,2个下标值的差(行号-列号)值相等。同理,斜率为+1的每一条斜线上,2个下标值的和(行号+列号)值相等。因此,若两个皇后防止的位置分别是(i,j)和(k,l),且i-j=k-l或i+j=k+l,则说明这两个皇后处于同一斜率上。以上两个方程分别等价于i-k=j-l和i-k=l-j。由此可知,只要|i-k|=|j-l|成立,就表明两个皇后位于同一条斜率上。问题的隐约束就变成了显约束。

用回溯法解n后问题时,用完全n叉树表示解空间。可行性约束Place减去不满足行、列和斜线约束的子树。

代码求解

import java.util.Scanner;
public class NQueen {
    final static int num=20;
    static int n;//皇后个数
    static int[]x = new int[num]; //当前解
    static long sum;
    public static boolean place(int k){
        for(int j=1;jn) sum++;
        else{
            for(int i=1;i<=n;i++){
                x[t]=i;
                if(place(t)) backTrack(t+1);
            }
        }
    }
    public static void main(String[] args){
        Scanner scan = new Scanner(System.in);
        n =scan.nextInt();
        sum=0;
        backTrack(1);
        System.out.println(sum);
    }
    
}

你可能感兴趣的:(2018-08-10)