问题讲述
八皇后问题,是一个古老而著名的问题,是回溯算法的典型例题。该问题是十九世纪著名的数学家高斯1850年提出:在8X8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。 高斯认为有76种方案。1854年在柏林的象棋杂志上不同的作者发表了40种不同的解,后来有人用图论的方法解出92种结果。计算机发明后,有多种方法可以解决此问题。
问题分析
现有一个8*8的网格 我们有8个皇后 需要将这8个皇后摆放到网格中使他们相互之间不能攻击彼此
我们首先想到的应该就是循环循环的确可以解除节,但是时间复杂度太高不可取
递归+回溯
我们可以利用递归来实现 因为我们 要做的事情其实就是一件事 判断当前位置可否放网格,那么我们就可以创建一个实现这个功能的函数然后反复调用。指导奖所有网格都判断结束
上述虽然能够找到解,但是找不到所有的解。所以我们就有用到了回溯,返回上一步或者上几步。那好直接上代码。用代码进行解释
package com.qiao.eq;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class Place {
int m = 0;
int a[][] = new int[9][9];
//创建一个数组存放皇后
List<Object> list = new ArrayList<Object>();
//创建一个list表单 添加记录
public void getA(int a[][]) {
this.a = a;
}
//获取数组
//判断那个位置可以放置皇后,并记录
public void putQueen(int n) {
if(n<9) {
for(int i=1;i<=8;i++) {
//判断该行的每个为值 如果 该位置可以摆放皇后 该位置值赋值为 1 跳转到下一行 知道这种方案结束 返回 该位置 将该值 重新赋值为0
//判断该位置能否放置皇后
if(RowJudge(n,a)==1&&LineJudge(i,a)==1&&PrincipalDiagonal(n,i,a)==1&&FollowDiagonal(n,i,a)==1) {
a[n][i] = 1; // 满足条件 赋值为1
if(n==8) {
//如果 n == 8 及该皇后为最后一个皇后 有因为经过判断 该位置可以放皇后 所以 这是一种摆放方法
m++;
//m记录方案数量
int b[][] = a;
//创建一个新的数组 存储这种方案的摆放方式
list.add(b);
//将新的数组 存放到 list中 一种存储方式
}
putQueen(n+1);
//继续调用 判断下一行 的八个位置能否摆放皇后
a[n][i] = 0;
//将 该位置的 值从新赋值为0 方便进行下一次判断 。
}
}
}
}
//判断行是否已经有皇后
public int RowJudge(int i,int a[][]) {
int j;
for(j=1;j<=8;j++) {
if(a[i][j]==1) {
return 0;
}
}
return 1;
}
//判断列是否已经有皇后
public int LineJudge(int i,int a[][]) {
int j;
for(j=1;j<=8;j++) {
if(a[j][i]==1) {
return 0;
}
}
return 1;
}
//判断主对角线是否有皇后 左上及右下
public int PrincipalDiagonal(int i,int j,int a[][]) {
for(int m = j,n = i;n<=8;n++,m++) {
if(m>8) {
break;
}
if(a[n][m]==1) {
return 0;
}
}
for(int m = j,n = i;n>=1;n--,m--) {
if(m<1) {
break;
}
if(a[n][m]==1) {
return 0;
}
}
return 1;
}
//判断从对角线是否有皇后 左下及右上
public int FollowDiagonal(int i,int j,int a[][]) {
for(int m = j,n = i;n<=8;n++,m--) {
if(m<1) {
break;
}
if(a[n][m]==1) {
return 0;
}
}
for(int m = j,n = i;n>=1;n--,m++) {
if(m>8) {
break;
}
if(a[n][m]==1) {
return 0;
}
}
return 1;
}
}
算法流程分析
首先 我初始化变量将数组所有值均赋值为0 然后 机型循环调用 为了找到所有方案 所以我采用行递归 即 每一次判断一整行
⑴ 判断该行每一个位置 如果当前位置满足条件往下执行⑵ 不满足 条件继续判断下一列
⑵ 将该位置的值赋值为1
⑶ 判断该行是否为第八行 及摆放的是否是最后一个皇后 如果是 从⑷执行 反之 从⑹开始执行
⑷ 方案数加一
⑸ 将该方案添加到list中
⑹ 继续判断下一行 如果行数大于9 该递归路径到此结束返回上一级
⑺ 将上一行的满足条件的那个值重新赋值为0 继续判断下一列 如果 满足条件从⑵开始执行
⑻ 如果 该行所有列均不满足条件 同样返回上一级 从⑺开始执行
反复执行改过程直到所有可能均找到。