关于八皇后问题求解

问题的提出

在1848年,国际西洋棋棋手马克斯·贝瑟尔提出了这样的一个问题,

在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问一共有多少种摆法。

八皇后问题求解

我第一时间就是想到定义一个二维数组去存储这个棋盘 用1表示皇后的位置 0表示没有空位置

//初始化 棋盘 
  int[][] arr = {
                {0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0},
        };

思路:

  1. 在棋盘中 一行一行的往下走 每一行就放一个 然后判断在当前位置中是否可以放皇后
  2. 写方法判断当前位置 是否可以放皇后
  3. 使用回溯 如果当前位置不可以放皇后的话 就返回上一行 以此类推
  4. 当行数走到第8行时(数组是0-7行)表示已经走到底了 完成了一种摆法

实现

  1. 写方法判断当前位置 是否可以放皇后
 /**
     * 判断行列是否可以
     *
     * @param x  当前的位置的行数
     * @param y  当前的位置的列数
     * @return  true 表示可以放皇后  否则不行
     */
    public static boolean rowAndList(int[][] arr, int x, int y) {
        arr[x][y] = 0;

        //判断行 行不行   int[x][i]
        for (int i = 0; i < 8; i++) {
            if (arr[x][i] == 1 || arr[i][y] == 1) {
                arr[x][y] = 1;
                return false;
            }
        }
        arr[x][y] = 1;
        return true;
    }

    /**
      * 判断行列是否可以
     *
     * @param x  当前的位置的行数
     * @param y  当前的位置的列数
     * @return  true 表示可以放皇后  否则不行
     */
    public static boolean xie(int[][] arr, int x, int y) {

        arr[x][y] = 0;

        // 判断右斜 行不行   int[x][y]
        for (int i = 0; i < 8; i++) {

            if ((x + i) <= 7 && (y + i) <= 7) {
                if (arr[x + i][y + i] == 1) {
                    arr[x][y] = 1;
                    return false;
                }
            }
            if ((x - i) >= 0 && (y - i) >= 0) {
                if (arr[x - i][y - i] == 1) {
                    arr[x][y] = 1;
                    return false;
                }
            }

            if ((x + i) <= 7 && (y - i) >= 0) {
                if (arr[x + i][y - i] == 1) {
                    arr[x][y] = 1;
                    return false;
                }
            }
            if ((x - i) >= 0 && (y + i) <= 7) {
                if (arr[x - i][y + i] == 1) {
                    arr[x][y] = 1;
                    return false;
                }
            }
        }
        arr[x][y] = 1;
        return true;
    }
  1. 回溯
 for (int i = 0; i < arr[index].length; i++) {
 //			将当前位置置为1
            arr[index][i] = 1;
            // 判断当前位置是否可以放1
            if (rowAndList(arr, index, i) && xie(arr, index, i)) {
            //方法名  回溯
                read(index + 1, arr);
            }
            arr[index][i] = 0;
        }
        //终止
        return arr;
  1. 当行数走到第8行时(数组是0-7行)表示已经走到底了 完成了一种摆法
if (index >= arr[0].length) {
            /**
             * 这里可以将所有情况都打印出来
             */
            sum++;
            System.out.println("第"+sum+"种");
            for (int i = 0; i < 8; i++) {
                for (int j = 0; j < 8; j++) {
                    System.out.print(arr[i][j] + "\t");
                }
                System.out.println();
            }
            System.out.println();
            return;
        }

源代码

package WanBanXueXi.task.day_11_28;


/**
 * 八皇后解法
 * 0 1 0 0 0 0 0 0 0
 * 0 0 0 1 0 0 0 0 0
 * 0 0 0 0 0 1 0 0 0
 * 1 0 0 0 0 0 0 1 0
 * 0 0 1 0 0 0 0 0 0
 * 0 0 0 0 1 0 0 0 0
 * 0 0 0 0 0 0 1 0 0
 * 0 0 0 0 0 0 0 0 1
 * <p>
 * 1 0 0 0 0 0 0 0 0
 * 0 0 1 0 0 0 0 0 0
 * 0 0 0 0 1 0 0 0 0
 * 0 0 0 0 0 0 1 0 0
 * 0 1 0 0 0 0 0 0 0
 * 0 0 0 1 0 0 0 0 0
 * 0 0 0 0 0 1 0 0 0
 * 0 0 0 0 0 0 0 1 0
 * <p>
 * 用下标表示     如果有11    那么  1*都不行     *1都不行   22 33 44 55 66 77 88都不行
 * 如果有23    那么
 * 1.横竖  2* *3 不行
 * 2.右斜  将23都加一   不行    34 45 56 78  减一也不行  12
 * 3.左斜    (32 41 14)不行    前加1 后减一  或 前减1   后减1
 * <p>
 * 回溯
 * <p>
 * 1.穷举法
 * 2.随机法
 */


public class EigthQueenAllPossible {
    static int sum = 0;

    public static void main(String[] args) {
        long begin = System.currentTimeMillis();

        int[][] arr = {
                {0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0},
        };


        read(0,arr);
        System.out.println(sum);
        System.out.println("总耗时:\t" + (System.currentTimeMillis() - begin) + "ms");
    }

    public static void read(int index, int[][] arr) {
        if (index >= arr[0].length) {
            /**
             * 这里可以将所有情况都打印出来
             */
            sum++;
            System.out.println("第"+sum+"种");
            for (int i = 0; i < 8; i++) {
                for (int j = 0; j < 8; j++) {
                    System.out.print(arr[i][j] + "\t");
                }
                System.out.println();
            }
            System.out.println();
            return;
        }
        for (int i = 0; i < arr[index].length; i++) {
            arr[index][i] = 1;
            if (rowAndList(arr, index, i) && xie(arr, index, i)) {
                read(index + 1, arr);
            }
            arr[index][i] = 0;
        }
        return;
    }

    /**
     * 判断行列是否可以
     *
     * @param x
     * @param y
     * @return
     */
    public static boolean rowAndList(int[][] arr, int x, int y) {
        arr[x][y] = 0;

        //判断行 行不行   int[x][i]
        for (int i = 0; i < 8; i++) {
            if (arr[x][i] == 1 || arr[i][y] == 1) {
                arr[x][y] = 1;
                return false;
            }
        }
        arr[x][y] = 1;
        return true;
    }

    /**
     * 判断斜是否可以
     *
     * @param x
     * @param y
     * @return
     */
    public static boolean xie(int[][] arr, int x, int y) {
//        a[3][2]
        arr[x][y] = 0;

        //todo 判断右斜 行不行   int[x][y]
        for (int i = 0; i < 8; i++) {

            if ((x + i) <= 7 && (y + i) <= 7) {
                if (arr[x + i][y + i] == 1) {
                    arr[x][y] = 1;
                    return false;
                }
            }
            if ((x - i) >= 0 && (y - i) >= 0) {
                if (arr[x - i][y - i] == 1) {
                    arr[x][y] = 1;
                    return false;
                }
            }

            if ((x + i) <= 7 && (y - i) >= 0) {
                if (arr[x + i][y - i] == 1) {
                    arr[x][y] = 1;
                    return false;
                }
            }
            if ((x - i) >= 0 && (y + i) <= 7) {
                if (arr[x - i][y + i] == 1) {
                    arr[x][y] = 1;
                    return false;
                }
            }
        }
        arr[x][y] = 1;
        return true;
    }
}

总结

这种使用回溯 解决的问题 我觉的还是有点难理解的 可以对着程序 慢慢debug 去理解
还有种简单的解法
随机算法
随机生成8个位置的坐标 然后去判断 这一次的结果 是不是成立
我朋友跑了两三个小时也没有跑出来(笑死) (不推荐)


补充n皇后问题 其实只要修改 一些代码就行

N皇后源代码

package WanBanXueXi.task.day_11_28;


/**
 * 八皇后解法
 * 0 1 0 0 0 0 0 0 0
 * 0 0 0 1 0 0 0 0 0
 * 0 0 0 0 0 1 0 0 0
 * 1 0 0 0 0 0 0 1 0
 * 0 0 1 0 0 0 0 0 0
 * 0 0 0 0 1 0 0 0 0
 * 0 0 0 0 0 0 1 0 0
 * 0 0 0 0 0 0 0 0 1
 * <p>
 * 1 0 0 0 0 0 0 0 0
 * 0 0 1 0 0 0 0 0 0
 * 0 0 0 0 1 0 0 0 0
 * 0 0 0 0 0 0 1 0 0
 * 0 1 0 0 0 0 0 0 0
 * 0 0 0 1 0 0 0 0 0
 * 0 0 0 0 0 1 0 0 0
 * 0 0 0 0 0 0 0 1 0
 * <p>
 * 用下标表示     如果有11    那么  1*都不行     *1都不行   22 33 44 55 66 77 88都不行
 * 如果有23    那么
 * 1.横竖  2* *3 不行
 * 2.右斜  将23都加一   不行    34 45 56 78  减一也不行  12
 * 3.左斜    (32 41 14)不行    前加1 后减一  或 前减1   后减1
 * <p>
 * 回溯
 * <p>
 * 1.穷举法
 * 2.随机法
 */


public class EigthQueenAllPossible {
    static int sum = 0;

    public static void main(String[] args) {
        long begin = System.currentTimeMillis();

        //皇后的数量
        int N = 8;

        int[][] arr = new int[N][N];

        for (int i = 0; i < arr.length; i++) {
            for (int j = 0; j < arr[i].length; j++) {
                arr[i][j] = 0;
            }
        }

        read(0,arr);
        System.out.println(sum);
        System.out.println("总耗时:\t" + (System.currentTimeMillis() - begin) + "ms");
    }

    public static void read(int index, int[][] arr) {
        if (index >= arr[0].length) {
            /**
             * 这里可以将所有情况都打印出来
             */
            sum++;
            System.out.println("第"+sum+"种");
            for (int i = 0; i < arr.length; i++) {
                for (int j = 0; j < arr.length; j++) {
                    System.out.print(arr[i][j] + "\t");
                }
                System.out.println();
            }
            System.out.println();
            return;
        }
        for (int i = 0; i < arr[index].length; i++) {
            arr[index][i] = 1;
            if (rowAndList(arr, index, i) && xie(arr, index, i)) {
                read(index + 1, arr);
            }
            arr[index][i] = 0;
        }
        return;
    }

    /**
     * 判断行列是否可以
     *
     * @param x
     * @param y
     * @return
     */
    public static boolean rowAndList(int[][] arr, int x, int y) {
        arr[x][y] = 0;

        //判断行 行不行   int[x][i]
        for (int i = 0; i < arr.length; i++) {
            if (arr[x][i] == 1 || arr[i][y] == 1) {
                arr[x][y] = 1;
                return false;
            }
        }
        arr[x][y] = 1;
        return true;
    }

    /**
     * 判断斜是否可以
     *
     * @param x
     * @param y
     * @return
     */
    public static boolean xie(int[][] arr, int x, int y) {
//        a[3][2]
        arr[x][y] = 0;

        //todo 判断右斜 行不行   int[x][y]
        for (int i = 0; i < arr.length; i++) {

            if ((x + i) <= arr.length-1 && (y + i) <= arr.length-1) {
                if (arr[x + i][y + i] == 1) {
                    arr[x][y] = 1;
                    return false;
                }
            }
            if ((x - i) >= 0 && (y - i) >= 0) {
                if (arr[x - i][y - i] == 1) {
                    arr[x][y] = 1;
                    return false;
                }
            }

            if ((x + i) <= arr.length-1 && (y - i) >= 0) {
                if (arr[x + i][y - i] == 1) {
                    arr[x][y] = 1;
                    return false;
                }
            }
            if ((x - i) >= 0 && (y + i) <= arr.length-1) {
                if (arr[x - i][y + i] == 1) {
                    arr[x][y] = 1;
                    return false;
                }
            }
        }
        arr[x][y] = 1;
        return true;
    }
}
  • 5
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值