引入

八皇后问题:是一个古老而著名的问题,是回溯算法的典型案例。该问题是国际西洋棋棋手马克斯·贝瑟尔于1848 年提出:在 8×8 格的国际象棋上摆放八个皇后,使其不能互相攻击,即: 任意两个皇后都不能处于同一行 、 同一列或同一斜线上,问有多少种摆法(92)。

根据排列组合:C64 取8,一共有4.426×10的9次方种方案

不难发现,每一行只能放一个皇后,所以8!=40320种方案

然后在40320种方案中,挑选符合题意的方案!

八皇后地图


根据条件我们可知每行每列最多都只能有一个皇后,这样可以在一定程度上缩减问题的规模。在第一行的某一列选择放置一个皇后,共有8种不同的选择,而第二行只能选择剩下的7列,也就是7种选择,剩下每一行的选择都会递减1,
那么总共可供选择的方案有8的阶乘种,已经是一种远优于暴力解法的解法,
但是这个阶乘的时间复杂度恐怕也难以令人接受,还有更优的解法吗?

解法

  • 回溯递归法
  • 回溯非递归法
  • 生成遍历法

回溯递归法

回溯递归法基本框架

int a[n];Queens(int k){if(k==n){//最后行皇后摆放okreturn}for (int i = 下界; i <=上界; i++) {//从当前行第一列开始遍历当前行所有列可能出现的位置a[k]=i;//放一个皇后if(check(k)){//满足的约束条件,符和则放下一行位置的皇后Queens(k+1);}//如果此位置皇后位置不合法,则回溯到当前行的下一列的位置(i++)继续递归搜索}}

基本思路:

  1. 第一个皇后先放第一行第一列
  2. 第二个皇后放在第二行第一列、然后判断是否 OK, 如果不 OK,继续放在第二列、第三列、依次把所有列都
    放完,找到一个合适
  3. 继续第三个皇后,还是第一列、第二列……直到第 8 个皇后也能放在一个不冲突的位置,算是找到了一个正确 解
  4. 当得到一个正确解时,在栈回退到上一个栈时,就会开始回溯,即将第一个皇后,放到第一列的所有正确解, 全部得到.
  5. 然后回头继续第一个皇后放第二列,后面继续循环执行 1,2,3,4 的步骤

小结:当我们选择了第一个皇后的位置之后,与其处于同行同列同斜线的位置便都无法被选择,第二个皇后只能放在未被第一个皇后所辐射到的位置上,接着放置第三个皇后,同样不能放在被前两个皇后辐射到的位置上,

  • 若此时已经没有未被辐射的位置能够被选择,也就意味着这种摆法是不可行的,我们需要回退到上一步,给第二个皇后重新选择一个未被第一个皇后辐射的位置,再来看是否有第三个皇后可以摆放的位置,如还是没有则再次回退至选择第二个皇后的位置,
  • 若第二个皇后也没有更多的选择则回退到第一个皇后,重新进行位置的选择。
  • 完成一次可行解即递归找到出口后,此时递归栈的栈顶会被弹出,次栈顶元素会被顶上,即下一行会继续搜索每列的位置,直到搜索到第一行所有列为止

图解

1.第一层递归,尝试在第一行摆放第一个皇后:

2.第二层递归,尝试在第二行摆放第二个皇后(前两格被第一个皇后封锁,只能落在第三格):

3.第三层递归,尝试在第三行摆放第三个皇后(前四格被第一第二个皇后封锁,只能落在第五格):

4.第四层递归,尝试在第四行摆放第四个皇后(第一格被第二个皇后封锁,只能落在第二格):

5.第五层递归,尝试在第五行摆放第五个皇后(前三格被前面的皇后封锁,只能落在第四格):

6.由于所有格子都“绿了”,第六行已经没办法摆放皇后,于是进行回溯,重新摆放第五个皇后到第八格。

7.第六行仍然没有办法摆放皇后,第五行也已经尝试遍了,于是回溯到第四行,重新摆放第四个皇后到第七格。

8.继续摆放第五个皇后,以此类推…

代码

package Algorithm.Recursion;/*** @author Jerssy* @version V1.0* @Description 递归回溯二维数组法* @create 2021-02-27 19:55*/
public class EightQueen4 {private  static  final  int MAX_QUEEN_LENGTH=8;private  int totalCount=0;private final int [][] queenArray=new int[MAX_QUEEN_LENGTH][MAX_QUEEN_LENGTH];private  void putQueens(int i){if (i==MAX_QUEEN_LENGTH) {//递归边界. 只要走到这里,所有皇后必然不冲突,找到一次可行解printQueens();return;}//遍历每行的每一列for (int j = 0; j < MAX_QUEEN_LENGTH; j++) {if(checkLegal(i,j)){queenArray[i][j]=1;//将此皇后放在第i行j列设置占位putQueens(i+1);//探测下一行所有的列//queenArray[i][j]=0;//每次递归完成即下一行皇后摆放出现不合法的则清空当前位置,并回溯到第i行j+1的位置即下一列①}queenArray[i][j]=0;//②此位置与①效果相同,因为校验位置失败则退出i+1的递归,继续执行下面代码}}private  boolean checkLegal(int n, int j){for (int i = 0; i < MAX_QUEEN_LENGTH; i++) {//检查行列if(queenArray[i][j]==1){return  false;}}//因为这里是在放好了一行的皇后后,接着在下一行的某列寻找合适位置,所以只需要检查前一行某列位置的皇后与当前位置的皇后是否存在冲突for (int k = n-1,m=j-1; k>=0&&m>=0; k--,m--) {//检查当前皇后的位置与当前位置的前一行所有列的左对角线if (queenArray[k][m]==1 ) {return false;}}for (int k = n-1,m=j+1; k>=0&&m<MAX_QUEEN_LENGTH; k--,m++) {//检查当前皇后的位置与当前位置的前一行所有列的右对角线if ( queenArray[k][m]==1 ) {return false;}}return true;}private void  printQueens(){totalCount++;System.out.println("第"+totalCount+"种解法---------------------------");for (int i = 0; i <MAX_QUEEN_LENGTH ; i++) {for (int j = 0; j <MAX_QUEEN_LENGTH; j++) {if (queenArray[i][j]==1){System.out.print(" * ");}else System.out.print(" 0 ");}System.out.println("");}}public static void main(String[] args) {long start= System.currentTimeMillis();EightQueen4 eightQueen4 = new EightQueen4();eightQueen4.putQueens(0);long end= System.currentTimeMillis();System.out.println("一共耗时"+(end-start));}
}

效果

使用 int Q[8][8]; 存储八皇后的数据,看起来比较直观,但是深入思考一下,每一行只存放1个数据,这样使用二维数组会造成空间的浪费,所以可使用 int Q[10];
来存储八个皇后的位置,比如 Q[0]:第0行皇后的列数 Q[1]:第1行皇后的列数 …

用一个一维数组即可解决问题. arr[8] =
{0 , 4, 7, 5, 2, 6, 1, 3} //对应 arr 下标 表示第几行,即第几个皇后,arr[i] = val , val 表示第 i+1 个皇后,放在第 i+1
行的第 val+1 列

改进一:使用一维数组

package Algorithm.Recursion;/*** @author Jerssy* @version V1.0* @Description 八皇后递归回溯一维数组法* @create 2021-02-27 9:56*/public class EightQueen {private  static   final  int maxCount=8;private  int  tailNumber=0;int[] queueArray=new  int[maxCount];public static void main(String[] args) {long start= System.currentTimeMillis();EightQueen eightQueens = new EightQueen();eightQueens. putQueens(0);long end= System.currentTimeMillis();System.out.println("一共存在的解:"+ eightQueens.tailNumber);System.out.println("一共耗时"+(end-start));}//校验皇后放的位置合法性private  boolean isLegal(int n){for (int i = 0; i < n; i++) {//当前行的元素与前一行(n-1)的元素位于相同的列或者位于斜线上//行号-列号之差绝对值相等说明在同一条对角线上if (queueArray[n]==queueArray[i]||Math.abs(queueArray[n] - queueArray[i]) ==Math.abs(n-i)) {return  false;}}return true;}//递归回溯放皇后private  void  putQueens(int n) {//这里产生了回溯,当递归找到出口后,此时递归栈的栈顶会被弹出,次栈顶元素会被顶上,即下一行会继续搜索每列的位置,直到搜索到第一行所有列为止if (n==maxCount) {//递归边界. 只要走到这里,所有皇后必然不冲突,找到一次可行解printQueens();return;}//遍历当前行的每一列for (int i = 1; i <=maxCount; i++) {queueArray[n]=i;//先把当前这个皇后 n , 放到该行的第 1 列if (isLegal(n)){//如果该位置皇后合法则递归放下一行的皇后putQueens(n+1);}//如果此位置皇后位置不合法,则回溯到当前行的下一列的位置(i++)}}private  void  printQueens(){tailNumber++;System.out.println("第"+tailNumber+"种解-----------------------------");for (int k : queueArray) {for (int j = 1; j <= maxCount; j++) {if (j == k) {System.out.print(" * ");} else System.out.print(" 0 ");}System.out.println("");}}
}

因为每放置一个皇后需要移动到下一行,不需要对该行判断,只需要对列主副对角线进行判断即可;
如何用一个值代表一条线呢?
平面坐标系中的副对角线实际上也就是二维数组中的主对角线

所以得出:

任意一条副对角线公式为
y = x + b => b = y - x + n(数组中没有负数所以平移n位)
任意一条主对角线公式为
y = - x + b => b = x + y

主对角线: rup[x+y]
副对角线: lup[y-x+n]

b 是任意一条主副对角线到(0,0)的截距

那我们就可以通过一个一维数组来表示二维数组中的每一条主副对角线

至多会有2*n条主或副对角线,所以只需要开2n的空间就可以了

改进二:使用主副对角线判断

package Algorithm.Recursion;/*** @author Jerssy* @version V1.0* @Description 八皇后递归回溯主副对角线法* @create 2021-02-28 10:38** 本质是递归回溯* 只是判断条件不同**  每放置一个皇后需要移动到下一行,不需要对该行判断,只需要对列主副对角线进行判断即可**  那么问题来了如何用一个值代表一条线呢** 列:  column[y]** 平面坐标系中的副对角线实际上也就是二维数组中的主对角线* 所以得出:* 任意一条副对角线公式为* y = x + b => b = y - x + n(数组中没有负数所以平移n位)* 任意一条主对角线公式为* y = - x + b => b = x + y** 主对角线: rup[x+y]* 副对角线: lup[y-x+n]** b 是任意一条主副对角线到(0,0)的截距** 那我们就可以通过一个一维数组来表示二维数组中的每一条主副对角线** 至多会有2*n条主或副对角线,所以只需要开2n的空间就可以了**/
public class EightQueen5 {private final int[] column; //同栏是否有皇后,1表示有private final int[] rup; //主对角线private final int[] lup; //副对角线private final int[] queen; //皇后位置private int num; //解法private  static   final  int maxCount=8;public EightQueen5() {column = new int[maxCount+1];rup = new int[2*maxCount+1];lup = new int[2*maxCount+1];for (int i = 1; i <=maxCount; i++)column[i] = 0;for (int i = 1; i <=2*maxCount; i++)rup[i] = lup[i] = 0;  //初始定义全部无皇后queen = new int[maxCount+1];}public void putQueens(int i) {if (i >maxCount) {printQueen();} else {for (int j = 1; j <=maxCount; j++) {//遍历当前行的所有列if ((column[j] == 0) && (rup[i+j] == 0) && (lup[i-j+maxCount] == 0)) {//若无皇后queen[i] = j; //设定为占用column[j] = rup[i+j] = lup[i-j+maxCount] = 1;putQueens(i+1);  //递归调用column[j] = rup[i+j] = lup[i-j+maxCount] = 0;}}}}private void printQueen() {num++;System.out.println("第"+num+"种解-----------------------------");for (int y = 1; y <= maxCount; y++) {for (int x = 1; x <= maxCount; x++) {if(queen[y]==x) {System.out.print(" * ");} else {System.out.print(" 0 ");}}System.out.println();}}public static void main(String[] args) {long start= System.currentTimeMillis();EightQueen5 queen = new EightQueen5();queen.putQueens(1);  //循环调用long end= System.currentTimeMillis();System.out.println("一共耗时"+(end-start));}
}

回溯非递归法

回溯法从问题本身出发,寻找可能出现的所有情况。和穷举法类似,但回溯法如果发现情况不存在就返回上一步继续尝试其他
分支,直到找到所有解或者搜索完所有分支为止

其策略为:能进则进,不能进则换,不能换则退

回溯非递归法基本框架(就是一般的回溯法)

int a[n];int i=1while(i>0){//有路可走,但没有回溯到第一行a[i]//设置第一个皇后的占位while(i<=n&& a[i]位置不合法){寻找a[i]下一个列的占位}if(在搜索范围内){if(i==n)//找到一组可行解打印皇后else{n++//继续寻找完整的解}}else{//回溯到上一行继续寻找占位,i--;并清空当前 a[i]的所占空间}}

回溯非递归法代码

package Algorithm.Recursion;/*** @author Jerssy* @version V1.0* @Description 八皇后解法:回溯法* @create 2021-02-27 18:03** 回溯法从问题本身出发,寻找可能出现的所有情况。和穷举法类似,但回溯法如果发现情况不存在就返回上一步继续尝试其他* 分支,直到找到所有解或者搜索完所有分支为止** 递归是从问题结果出发,不断的自己调用自己** 能进则进,不能进则换,不能换则退*** 回溯法框架:**    int a[n];int i=1*    while(i>0){//有路可走,但没有回溯到第一行*        a[i]//设置第一个皇后的占位*        while(i<=n&& a[i]位置不合法){*            寻找a[i]下一个列的占位*        }*        if(在搜索范围内){*            if(i==n)//找到一组可行解*              打印皇后*            else{*                n++//继续寻找完整的解*            }*        }*        else{*            //回溯到上一行继续寻找占位,i--;并清空当前 a[i]的所占空间*        }*    }**/
public class EightQueen3 {private  static  final  int MAX_QUEEN_LENGTH=8;private  int tailNumber=0;private final int[] queenArray=new int[MAX_QUEEN_LENGTH+1];//记录每列皇后的位置,从1的位置开始记录private  void putQueens(){int n=1;//代表行while (n>0){//找到一组可行解后此时n为8,则从当前行开始寻找此行其他的可行解,然后回溯到下一行继续寻找,直到第一行回溯完为止退出循环queenArray[n]++;while (queenArray[n]<=MAX_QUEEN_LENGTH&&!isLegal(n)){//遍历一行的所有列,如果不合法则继续找当前行的下一列位置,如果此行所有列均不合法则queenArray[n]代表的列数会自增到9queenArray[n]++;}//在搜索空间内if (queenArray[n]<=MAX_QUEEN_LENGTH) {//当前行第queenArray[n]列的皇后的位置符合条件,否则当前行所有列位置均不合法则需要回溯到上一行if(n==MAX_QUEEN_LENGTH){//找到一组解printQueens();}else n++;//没找全继续找}else {//不在则回溯到上一行,并清空占位queenArray[n]=0;n--;}}}//校验皇后放的位置合法性private  boolean isLegal(int n){for (int i = 1; i <n; i++) {//当前行的元素与前一行(n-1)的元素位于相同的列或者位于斜线上//行号-列号之差绝对值相等说明在同一条对角线上if (queenArray[n]==queenArray[i]||Math.abs(queenArray[n] - queenArray[i]) ==Math.abs(n-i)) {return  false;}}return true;}private  void  printQueens(){tailNumber++;System.out.println("第"+tailNumber+"种解-----------------------------");for (int i = 1; i <=MAX_QUEEN_LENGTH; i++) {for (int j = 1; j <= MAX_QUEEN_LENGTH; j++) {if (j == queenArray[i]) {System.out.print(" * ");} else System.out.print(" 0 ");}System.out.println("");}}public static void main(String[] args) {long start= System.currentTimeMillis();new  EightQueen3().putQueens();long end= System.currentTimeMillis();System.out.println("一共耗时"+(end-start));}
}

生成遍历法

package Algorithm.Recursion;/*** @author Jerssy* @version V1.0* @Description 八皇后解法:生成遍历法:先产生所有的可能,然后根据限制条件过滤结果* @create 2021-02-27 17:26** 此方法相比递归和回溯效率要差,因为回溯是只要当前分支无法继续搜素下去时候就会停止搜索,返回上一行寻找其他可行分支。*/public class EightQueen2 {int[] queueArray=new int[8]; int tailNumber = 0, maxCount = 8,executeNum=0;private void search(int n) {executeNum++;//执行次数//检查每个可能,看是否会冲突if(n == maxCount) {for(int i = 0; i < maxCount; i++) {//当前行位置的皇后for (int j = i + 1; j < maxCount; j++) {//下一行位置的皇后//当前行的元素与下一行的元素位于相同的列或者位于斜线上则冲突if (queueArray[i] == queueArray[j] || Math.abs(queueArray[i] - queueArray[j]) == Math.abs(i - j)) {return;}}}//找到一个没冲突的可能tailNumber++;}//遍历生成所有的可能else for(int i = 0; i < maxCount; i++) {queueArray[n] = i;search(n+1);}}public static void main(String[] args) {long start= System.currentTimeMillis();EightQueen2 eightQueue2 = new EightQueen2();eightQueue2.search(0);System.out.println("可行解:"+eightQueue2.tailNumber);System.out.println("一共执行次数:"+eightQueue2.executeNum);long end= System.currentTimeMillis();System.out.println("一共耗时"+(end-start));}
}

制作八皇后小游戏

搞清楚了八皇后问题下面可以开发个八皇后小游戏验证是否正确

先看效果图

一:绘制棋盘

 public  QueenFrame() {setSize(FRAME_WIDTH,FRAME_HEIGHT);setLocationRelativeTo(null);//窗口居中JPanel queenPanel = new JPanel();//棋盘初始化initialization(queenPanel);queenPanel.setLayout(new GridLayout(MAX_QUEEN_LENGTH,MAX_QUEEN_LENGTH));add(queenPanel,BorderLayout.CENTER);setResizable(false);setVisible(true);//关闭窗口事件addWindowListener(new WindowAdapter() {@Overridepublic void windowClosing(WindowEvent e) {System.exit(0);}});}//初始化棋盘private  void  initialization(JPanel queenPanel) {for (int i=0;i<MAX_QUEEN_LENGTH;i++){for (int j=0;j<MAX_QUEEN_LENGTH;j++){queenMap[i][j]=new QueenPanelMap(i,j);queenMap[i][j].unConflict=0;int finalI = i;int finalJ = j;//为每个棋格绑定鼠标点击事件queenMap[i][j].addMouseListener(new MouseAdapter() {@Overridepublic void mouseClicked(MouseEvent e) {setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));putQueens(e, finalI, finalJ);}});queenPanel.add(queenMap[i][j]);}}}

二 放置皇后

 //放置皇后private  void putQueens(MouseEvent e, int n , int j) {JPanel  panel=(JPanel) e.getComponent();if (panel.getComponents().length==0) {//如果当前棋格里没有放皇后QueenImage queenImage = new QueenImage();queenImage.setBackground(panel.getBackground());panel.add(queenImage,BorderLayout.CENTER);panel.validate();//添加了皇后组件重载此棋格容器lastLine=n;isChecked=false;if (!checkLegal(n, j)){System.out.println("游戏结束");JOptionPane.showMessageDialog(QueenFrame.this,"很遗憾,你输了");clearQueenMap();return;}queenMap[n][j].unConflict=1;totalNum++;if (totalNum==MAX_QUEEN_LENGTH) {//1 5 8 6 3 7 2 4int selectI = JOptionPane.showConfirmDialog(QueenFrame.this, "恭喜,你赢了!是否在来一次?", "提示",JOptionPane.YES_NO_OPTION);if (selectI == 0) {clearQueenMap();}}}else {//再次点击删除已放置的皇后panel.remove(panel.getComponents()[0]);panel.repaint();queenMap[n][j].unConflict=0;totalNum--;}}

三 验证八皇后问题

先看个错误的

在测试个通过的
正确的一种解法-- 1 5 8 6 3 7 2 4

完整代码

package Algorithm.Recursion;import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;/*** @author Jerssy* @version V1.0* @Description 模拟八皇后游戏* @create 2021-02-28 15:33** repaint()方法是重绘,而validate()是重载,一般来说,从一个容器中删除某个组件需要调用repaint(),而把某个组件添加到某一容器中,则需调用validate()* 当你改变一个会影响它们外观的属性时调用repaint();当你改变一个会影响它们宽度/高度的属性时, revalidate()被调用** invalidate()将容器标记为无效。意味着内容在某种程度上是错误的,必须重新布局。但它只是一种标志/旗帜。有可能以后必须刷新多个无效容器。** validate()执行重新布局。这意味着要求所有大小的无效内容,并且LayoutManager将所有子组件的大小设置为正确的值。* revalidate()只是两者的总和。它将容器标记为无效并执行容器的布局。**/
public class EightQueenGame {private static final int FRAME_WIDTH=600;//窗口长private static final int FRAME_HEIGHT=600;//窗口宽private  static  final  int MAX_QUEEN_LENGTH=8;//棋盘最大容量public static void main(String[] args) {new QueenFrame();}static class QueenFrame extends Frame {private final QueenPanelMap[][] queenMap=new QueenPanelMap[MAX_QUEEN_LENGTH][MAX_QUEEN_LENGTH];//棋盘数组private  int  totalNum=0;//记录步数private  int lastLine=0;//上一行private boolean isChecked=false;//是否校验过了private  int checkedLen=0;//校验次数public  QueenFrame() {setSize(FRAME_WIDTH,FRAME_HEIGHT);setLocationRelativeTo(null);//窗口居中JPanel queenPanel = new JPanel();//棋盘初始化initialization(queenPanel);queenPanel.setLayout(new GridLayout(MAX_QUEEN_LENGTH,MAX_QUEEN_LENGTH));add(queenPanel,BorderLayout.CENTER);setResizable(false);setVisible(true);//关闭窗口事件addWindowListener(new WindowAdapter() {@Overridepublic void windowClosing(WindowEvent e) {System.exit(0);}});}//初始化棋盘private  void  initialization(JPanel queenPanel) {for (int i=0;i<MAX_QUEEN_LENGTH;i++){for (int j=0;j<MAX_QUEEN_LENGTH;j++){queenMap[i][j]=new QueenPanelMap(i,j);queenMap[i][j].unConflict=0;int finalI = i;int finalJ = j;//为每个棋格绑定鼠标点击事件queenMap[i][j].addMouseListener(new MouseAdapter() {@Overridepublic void mouseClicked(MouseEvent e) {setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));putQueens(e, finalI, finalJ);}});queenPanel.add(queenMap[i][j]);}}}//放置皇后private  void putQueens(MouseEvent e, int n , int j) {JPanel  panel=(JPanel) e.getComponent();if (panel.getComponents().length==0) {//如果当前棋格里没有放皇后QueenImage queenImage = new QueenImage();queenImage.setBackground(panel.getBackground());panel.add(queenImage,BorderLayout.CENTER);panel.validate();//添加了皇后组件重载此棋格容器lastLine=n;isChecked=false;checkedLen=0;if (!checkLegal(n, j)){System.out.println("游戏结束");JOptionPane.showMessageDialog(QueenFrame.this,"很遗憾,你输了");clearQueenMap();return;}queenMap[n][j].unConflict=1;totalNum++;if (totalNum==MAX_QUEEN_LENGTH) {//1 5 8 6 3 7 2 4int selectI = JOptionPane.showConfirmDialog(QueenFrame.this, "恭喜,你赢了!是否在来一次?", "提示",JOptionPane.YES_NO_OPTION);if (selectI == 0) {clearQueenMap();}}}else {//再次点击删除已放置的皇后panel.remove(panel.getComponents()[0]);panel.repaint();queenMap[n][j].unConflict=0;totalNum--;}}//清空棋盘private  void clearQueenMap() {for (int i=0;i<MAX_QUEEN_LENGTH;i++){for (int j=0;j<MAX_QUEEN_LENGTH;j++){if (queenMap[i][j].getComponents().length!=0) {queenMap[i][j].remove(queenMap[i][j].getComponents()[0]);queenMap[i][j].repaint();}queenMap[i][j].unConflict=0;}}totalNum=0;}//校验皇后放的位置合法性private  boolean checkLegal(int n, int j)  {if (n ==MAX_QUEEN_LENGTH||n<0) {return true;}for (int k = 0; k < MAX_QUEEN_LENGTH; k++) {//校验当前行所有的列及当前列所有的行if (lastLine==n){if (queenMap[n][k].unConflict == 1||queenMap[k][j].unConflict==1) {return  false;}}else {//校验对角线if (Math.abs(j-k)==Math.abs(lastLine-n)) {if (queenMap[n][k].unConflict == 1) {return false;}}}}//校验当前行后面的行①checkedLen++;if (!isChecked&&!checkLegal(n+1,j)) {return false;}//这里定位到①位置递归开始的位置,否则②位置又从n=7的位置开始向上递归,这是完全不必要的因为这些位置已经在①步骤检查过了isChecked=true;System.out.println(n);return checkLegal(MAX_QUEEN_LENGTH-checkedLen - 1, j);//②校验当前行前面的行}}private  static class  QueenPanelMap extends  JPanel {private  int unConflict=0;public QueenPanelMap(int i,int j) {if ((j+i) %2==0) {setBackground(Color.WHITE);}else setBackground(Color.BLUE);}}private static class  QueenImage extends  JPanel {Image imageIcon;private static int dstWidth=0;private static int dstHeight=0;private static int maxWidth=0;private static int maxHeight=0;public QueenImage() {imageIcon= new ImageIcon("Algorithm\\src\\Algorithm\\Recursion\\queen.png").getImage();int srcWidth= imageIcon.getWidth(null);if (srcWidth<0) {throw  new RuntimeException("加载图片失败");}int srcHeight= imageIcon.getHeight(null);maxWidth=FRAME_WIDTH/MAX_QUEEN_LENGTH;maxHeight=FRAME_HEIGHT/MAX_QUEEN_LENGTH;dstWidth=srcWidth;dstHeight=srcHeight;float k;if (srcWidth>maxWidth){dstWidth=maxWidth;k=(float)srcWidth/(float)maxWidth;dstHeight=Math.round((float)srcHeight/k);}else if (srcWidth<maxWidth/2) {dstWidth=maxWidth/2;}srcHeight=dstHeight;if (srcHeight>maxHeight){dstHeight=maxHeight;k=(float)srcHeight/(float)maxHeight;dstWidth=Math.round((float)dstWidth/k);}else if (srcHeight < maxHeight / 2) {dstHeight=maxHeight;}}public void paintComponent(Graphics g){super.paintComponent(g);setBounds((maxWidth-dstWidth)/2-1,(maxHeight-dstHeight)/2-3,dstWidth,dstHeight);g.drawImage(imageIcon,0,0,dstWidth , dstHeight, this);}}
}

八皇后问题解法大全及编写八皇后小游戏相关推荐

  1. python小游戏代码大全-Python编写的点灯小游戏代码

    Python语言编写的点灯小游戏代码及思路如下: 点灯游戏及其求解的方法, 点灯游戏的游戏规则: (1)有个N行N列的灯板,当你开关其中一盏灯: (2)它和上下左右的灯的状态全部反转,目标是将全部的灯 ...

  2. java编写数字游戏大全_Java编写猜数字小游戏

    本文实例讲述了java实现的简单猜数字游戏代码.分享给大家供大家参考. 以下是java语言写的一个猜数字小游戏引用片段: import java.text.simpledateformat; impo ...

  3. 基于c++EGE图形库编写的五子棋小游戏

    基于c++EGE图形库编写的五子棋小游戏 EGE图形库 新手推荐使用 EGE(Easy Graphics Engine),是windows下的简易绘图库,是一个类似BGI(graphics.h)的面向 ...

  4. python 贪吃蛇小游戏代码_10分钟再用Python编写贪吃蛇小游戏

    Python编写贪吃蛇 前不久我们公众号发布了一篇C++编写贪吃蛇小游戏的推文,反响空前.看来大家对这类简单易上手小游戏还是很喜爱的. 恰逢2018年IEEE Spectrum编程语言排行榜新鲜出炉, ...

  5. c++编写手机小游戏代码_只需22行代码,用python编写自己的小游戏

    假期最后一天,有些人在外面玩累了,有些人躺在家里快发霉了,闲暇时候不如动动手做个小游戏玩一玩吧! 本文实例为大家分享了python编写猜数字小游戏的具体代码,供大家参考,具体内容如下 1 import ...

  6. main java game,playgame 一个JAVA编写的飞行小游戏,有基本完整的 框架,适合初学者参照学习 Other s 其他 238万源代码下载- www.pudn.com...

    文件名称: playgame下载 收藏√  [ 5  4  3  2  1 ] 开发工具: Java 文件大小: 7050 KB 上传时间: 2013-06-06 下载次数: 3 提 供 者: Lyq ...

  7. 10分钟用python编写贪吃蛇小游戏_牛得一批!10分钟用Python编写一个贪吃蛇小游戏...

    贪吃蛇,大家应该都玩过.当初第一次接触贪吃蛇的时候 ,还是能砸核桃的诺基亚上,当时玩的不亦乐乎.今天,我们用Python编程一个贪吃蛇游戏,下面我们先看看效果: 好了,先介绍一个思路 所有的游戏最主要 ...

  8. 【第三篇:利用ChatGPT编写贪食蛇小游戏】

    好像现在最近对ChatGPT讨论越来越热,ChatGPT的出现应该会引发"一次新的社会变革",未来很多码农会失业啊!与其坐着被改变,不如尝试主动改变,我今天就利用ChatGPT编写 ...

  9. 使用C语言编写三子棋小游戏

    使用C语言编写三子棋小游戏: 首先进行分析: 1.需要将游戏实现分为三个部分:头文件,函数功能实现,游戏组合测试. 2.游戏可以循环进行,不必多次打开,可采用 do...while循环结构. 3.游戏 ...

  10. python编写猜大小游戏_python编写猜数字小游戏

    本文实例为大家分享了python编写猜数字小游戏的具体代码,供大家参考,具体内容如下 import random secret = random.randint(1,30) guess = 0 tri ...

最新文章

  1. 这些Python常用的工具和学习资源你都知道么?
  2. Netty入门教程——认识Netty
  3. html5画布画点,在HTML5画布上绘制一个点
  4. 专用码计算机英语怎么说,计算机专用英语词汇整理
  5. 微软大法好不好,终于要对比了
  6. 使用 Nginx 部署静态页面
  7. Excel转批量转Csv工具软件
  8. 淘宝天猫京东商品详情一键铺货到拼多多平台店铺接口代码对接教程
  9. 《游戏系统设计四》游戏资源系统太复杂? 啥?你不会?一步一步带你分析并实现,源码直接拿走
  10. android 腾讯云聊天,腾讯云视频通话
  11. 计算机开启后显示器黑屏,电脑打开后显示器黑屏怎么办
  12. 软工学者Ming Wen及其顶会论文解读
  13. 提升领导力这7个法则,你不得不知道
  14. loopback接口介绍
  15. BAT 遍历文件夹和子文件夹下所有文件
  16. 数据库系统--码,超码,候选码,主属性,非主属性,主码,全码,外码基本概念
  17. 2023年英语二大作文押题猜想(达立易考)
  18. CRT (C run-time library)简介
  19. EventSystems之鼠标相关事件(实现拖曳功能常用)
  20. 电脑如何通过滑动关机?

热门文章

  1. C. Annoying Present(思维+数学)
  2. 机器人系统仿真(七)——xacro语法详解
  3. Docker磁盘空间使用分析与清理
  4. 利用requests模块爬取小说
  5. c++贪吃蛇源代码 完整版
  6. 京东商品详情查询接口V1新版接口
  7. 服务器网卡相关知识点
  8. 得力针式打印机第一联清晰第二联不清晰解决办法
  9. torch.masked_select和torch.masked_scatter
  10. 5分钟使用Unity制作AR应用,结合EasyAR制作AR(转)