题目介绍
八皇后问题,是一个古老而著名的问题,是回溯算法的典型案例。该问题是国际象棋棋手马克斯·贝瑟尔于1848年提出:在8×8格的国际象棋棋盘上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一对角线上,问有多少种摆法。高斯认为有76种方案。1854年柏林象棋杂志上不同的作者发表了40种不同的解,后来有人用图论的方法解出92种结果。
Input
无输入数据
Output
输出所有解
题目思路
根据规则我们可以得出每行必有一个皇后,则找指定皇后时只需在当行遍历。
首先根据规则找到一个皇后,然后根据规则把棋盘上不能有皇后点全部标记,再在剩下的棋盘上找下一个没被标记的皇后,如果找不到则回溯。
回溯:这个操作需要在每一步结束时加个“快照”,以便于回溯
具体代码
package com.dreamchaser; import java.util.Stack; /** * 八皇后问题 * 每行都肯定有一个皇后 */ public class test4 { //维护一个当前正在处理的矩阵 static int[][] finalCheckerBoard=new int[8][8]; static Stack<Step> stack=new Stack<Step>(); /** * 控制循环的开关 */ static boolean flag=true; public static void main(String[] args) { /** * 第n组解 */ int n=0; //初始值 Spot spot=findOne(finalCheckerBoard,stack.size()+1); while (flag){ Step step=new Step(); if (spot!=null){ //若找到则将这个点处理后的棋盘与原来棋盘合并,然后入栈 int[][] c; c=handle(spot); finalCheckerBoard=merge(c,finalCheckerBoard); //赋值给step,相当于给当前步骤存档,以便回溯 step.setSpot(spot); step.setCheckerboard(finalCheckerBoard); step.setNumber(stack.size()+1); //步骤入栈 stack.push(step); spot=findOne(finalCheckerBoard,stack.size()+1); if (stack.size()==8){ Stack<Step> steps= (Stack<Step>) stack.clone(); n++; System.out.println("第"+n+"组解:"); while (steps.size()>0){ System.out.println(steps.pop().spot); } recall(); } }else{ //若没找到,则回溯 spot=recall(); } } } /** * 回溯,返回上一步的下一个点,如果没有下一个点则放回null * @return 上一步的下一个点 */ private static Spot recall(){ Step step=stack.pop(); Spot spot=step.getSpot(); if (spot.getY()<7){ //处理finalCheckerBoard if (stack.isEmpty()){ //如果堆栈是空的话,则赋值一个初始值 finalCheckerBoard=new int[8][8]; for (int j=0;j<= spot.getY();j++){ finalCheckerBoard[spot.getX()][j]=1; } }else { //如果不为空,则直接从上一步中取值 finalCheckerBoard=stack.peek().getCheckerboard(); //因为之前没做过标记,这里回溯时前进一个防止重复 finalCheckerBoard[spot.getX()][spot.getY()]=1; } return findOne(finalCheckerBoard, step.getNumber()); } if (stack.isEmpty()&&spot.getX()==0&&spot.getY()==7){ flag=false; } //如果等于7,说明此皇后遍历完了,下一次得从上一个开始遍历 return null; } /** * 在处理好的棋盘中找第number个皇后可以摆放的位置 * @param handledcheckerboard 处理好的棋盘 * @param number 第number个皇后 * @return 摆放的位置 */ private static Spot findOne(int[][] handledcheckerboard,int number) { Spot spot=new Spot(); int i=number-1; for (int j=0;j<8&&i<8;j++){ if (handledcheckerboard[i][j]==0){ spot.x=i; spot.y=j; return spot; } } return null; } /** * 处理棋盘 * @param spot 皇后坐标 * @return 处理好的棋盘 */ private static int[][] handle(Spot spot) { int x= spot.x; int y= spot.y; int[][] checkerboard=new int[8][8]; for (int j=0;j<8;j++){ checkerboard[x][j]=1; } for (int i = 0; i < 8; i++) { checkerboard[i][y]=1; } //处理对角线 for (int i=0,j=y-x;i<8;i++,j++){ if (j>=0&&j<8){ checkerboard[i][j]=1; } } for (int i=0,j=x+y;i<8;i++,j--){ if (j>=0&&j<8){ checkerboard[i][j]=1; } } return checkerboard; } /** * 合并处理好的棋盘 * @param checkerboards 处理好的棋盘 * @return 合并好的棋盘 */ private static int[][] merge(int[][]...checkerboards) { int[][] checkerboard=new int[8][8]; for (int[][] c:checkerboards){ for (int i=0;i<8;i++){ for (int j=0;j<8;j++){ if (c[i][j]==1){ checkerboard[i][j]=1; } } } } return checkerboard; } /** * 记录点的坐标 */ private static class Spot{ int x; int y; public Spot() { } public Spot(int x, int y) { this.x = x; this.y = y; } public int getX() { return x; } public void setX(int x) { this.x = x; } public int getY() { return y; } public void setY(int y) { this.y = y; } @Override public String toString() { return "Spot{" + "x=" + x + ", y=" + y + '}'; } } /** * 记录每一步,便于存储和回溯 */ private static class Step{ Spot spot; int[][] checkerboard; //记录序号 int number; public Step() { } public Step(Spot spot, int[][] checkerboard, int number) { this.spot = spot; this.checkerboard = checkerboard; this.number = number; } public Spot getSpot() { return spot; } public void setSpot(Spot spot) { this.spot = spot; } public int[][] getCheckerboard() { return checkerboard; } public void setCheckerboard(int[][] checkerboard) { this.checkerboard = checkerboard; } public int getNumber() { return number; } public void setNumber(int number) { this.number = number; } } }
运行截图