八皇后

八皇后

八皇后问题的描述一般是这样的:每个皇后能够攻击他所在的行、列、以及斜边,在n*n的棋盘上如何放置n个皇后让他们不相互攻击?

在解决这个问题之前我们要先了解两个东西:

  • 如何实现排列(这个可以看我之前写的如何实现排列和组合)
  • 如何解决斜边的标记问题

关于行和列的标记就不多说废话了.直接来看如何实现斜边的标记

5 (5,1) (5,2) (5,3) (5,4) (5,5)
4 (4,1) (4,2) (4,3) (4,4) (4,5)
3 (3,1) (3,2) (3,3) (3,4) (3,5)
2 (2,1) (2,2) (2,3) (2,4) (2,5)
1 (1,1) (1,2) (1,3) (1,4) (1,5)
  • | 1 | 2 | 3 | 4 | 5

我们直接来看这个数组,姑且先把斜边分为与主对角线平行的与副对角线平行的两类.

  • 先来观察与主对角线平行的斜边,会发现这条斜边上的每个点的行+列的值是相同的.
    如5+1=6 4+2=6 3+3=6 ....

  • 再来观察与副对角线平行的斜边,会发现这条斜边上的每个点的行-列的值是相同的.
    如5-5=0 4-4=0 3-3=0 ....

了解了这个之后就好解决问题了.利用这个性质可以对排列进行剪枝(或者说回溯?)

直接上代码

import java.util.LinkedList;
import java.util.Scanner;

public class DFS03 {


    static int count = 0;// 符合条件的个数
    static int n;// 棋盘大小n*n
    static LinkedList<Integer> place = new LinkedList<>();
    // 皇后出现的位置
    static boolean[] flag1 = new boolean[50], flag2 = new boolean[50], flag3 = new boolean[50];
    // 皇后能够影响的列,主对角线,和副对角线
    // 使用的数组声明大一些,防止出现数组越界

    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        n = scan.nextInt();
        dfs(1);
        System.out.println(count);
    }

    static void dfs(int h) {
        if (h > n) {
            System.out.println(place);
            count++;
            return;
        }
        for (int i = 1; i <= n; i++) {
            if (!flag1[i] && !flag2[h + i] && !flag3[h - i + n]) {
                //如果都i对应的列和主对角线和副对角线都没有被影响到
                place.add(i);
                flag1[i] = true;//标记
                flag2[h + i] = true;//标记
                flag3[h - i + n] = true;//标记
                dfs(h + 1);
                place.removeLast();
                flag1[i] = false;//取消标记
                flag2[h + i] = false;//取消标记
                flag3[h - i + n] = false;//取消标记
            }

        }
    }

}

  • 关于标记副对角线还需要加一个偏置值,因为副对角线的行-列的值会出现负值.不加偏置值会造成索引为负的情况.

  • 不要说为什么代码没有去标记行,本身第一个数就是代表第一行,第二个数代表第二行.....当然不需要标记啦.

posted @ 2020-03-10 22:32  continued258  阅读(137)  评论(0)    收藏  举报