数据结构与算法之递归(8皇后问题)

1. 规则:有一个 8 x 8 的棋盘,放置皇后棋子,要求:所放的皇后不能在同一排,不能在同一列,不能在同一斜线

2. http://www.4399.com/baidugame/42643.htm  这个是4399里8皇后小游戏的地址

3. 为了理清思路,我以 4 x 4的棋盘为例,code

/**
 * 8皇后问题
 */
public class Queue8 {

    // 一维数组代表所放皇后的列, 我们默认不把皇后放在同一行
    private final int max = 4;
    private final int[] array = new int[max];
    private static int count = 0;

    public static void main(String[] args) {
        Queue8 queue8 = new Queue8();
        queue8.placeChess(0);
        System.out.printf("4 x 4的棋盘解法有%d种\n", count);
    }

    /**
     * 放置棋子
     *
     * @param n 棋盘行数索引
     */
    public void placeChess(int n) {
        if (n < 0 || n > max) {
            return;
        }
        if (n == max) {
            print();
            return;
        }
        for (int i = 0; i < max; i++) {
            array[n] = i; // i就是表示第n行的第i列(n和i都是索引)
            if (isNotConflict(n)) {
                placeChess(n + 1);
            } else { // 这一块代码可能有点多余, 但是可以帮助理解: 如果冲突则将棋子放到下一列
                continue;
            }
        }
    }

    /**
     * 判断第n行放的皇后是否和其他行冲突
     *
     * @param n 行索引
     * @return boolean
     */
    private boolean isNotConflict(int n) {
        // 拿出第n行前面的所有行, 一行一行的和第n行做对比(array[n]表示第n行的第array[n]列, array[i]同理)
        for (int i = 0; i < n; i++) { // 这里出错了一次: 一开始写成i < max, 结果放置第一个棋子时出错, 导致以后的都会错
            // 第一种情况:同一行,不用判断。因为我们默认的摆放就是不在同一行
            // 第二种情况:同一列, array[i] 和 array[n] 就表示第i行和第n行的列数, 相等就是在同一列
            // 第三种情况:同一斜线, 在同一斜线的斜率的绝对值应该等于1, 举个例子坐标(2, 1)和坐标(3, 0)在同一条斜线上(或者这么说, 在一条斜线上的两个点x轴与y轴的差值的绝对值相同)
            if (array[i] == array[n] || Math.abs(n - i) == Math.abs(array[n] - array[i])) {
                return false;
            }
        }
        return true;
    }

    /**
     * 打印皇后位置
     */
    private void print() {
        count++;
        for (int value : array) {
            System.out.print(value + " ");
        }
        System.out.println();
    }
}


// 执行的结果
1 3 0 2 
2 0 3 1 
4 x 4的棋盘解法有2种

4. 画图,看一下它的执行思路

5. 总结

1)代码不多,但是理解起来其实还是挺费劲的,就是要对递归求解时有个印象。

2)每一层都要开一个方法栈,以 4 x 4的棋盘为例,最多开五个栈:

  • 前四个栈方法中,每个方法栈中都要执行for循环,且参数i都需要从0遍历到3,没有跳步
  • 第五个栈的作用是找到解法之后,打印解法并终止递归
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值