借鉴:
https://blog.csdn.net/piyongduo3393/article/details/86497081
https://blog.csdn.net/gui951753/article/details/79677785?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase
其实这是一个回溯问题,或者通俗一点就是递归问题。
有点像是青蛙的台阶跳一线,先看第一步怎么走,下一步在增么走,这里也是一样的,先看第一行的皇后在哪一列,假设在第一行的第一列,那么按照其规则,整行整列都不可再用了,即第一行不可用,第一列不可用,并且按照如下的函数来说明你的哪一个格子不能放置皇后
上斜线,即斜率为1的一元一次方程:
y = x+b ,假设此时皇后在第(i,j)个格子,带入方程就是 j = i+b,b = j-i;
所以最终的方程就是 y = x+j-i ;
那么将y从0到n,挨个的计算出需要加1 的格子位置,那么此时的方程就是x = y-j+i;当然你也可以反着来,从x开始0到n,计算y,y = x+j-i;
下斜线,即斜率为-1的一元一次方程:
y = -x+b ,假设此时皇后在第(i,j)个格子,带入方程就是 y = -x+i+j;
那么将x从0到n来计算每一个需要加以的格子。
上面用一个hashset来填充所有已计算过的格子,即重复的格子不需要在计算。
清空就是反着来。
代码:
import java.util.ArrayList;
import java.util.HashSet;
public class n_皇后问题 {
ArrayList<ArrayList<Integer>> lists = new ArrayList<>();
ArrayList<Integer> list = new ArrayList<>();
public n_皇后问题(){
int n = 10;
int[][] tu = new int[n][n];
//初始化
for (int i = 0; i < tu.length; i++) {
for (int i1 = 0; i1 < tu.length; i1++) {
tu[i][i1] = 0;
}
}
N_back(n,0,tu);
System.out.println(lists.size());
for (ArrayList<Integer> integers : lists) {
for (Integer integer : integers) {
System.out.print(integer+" ");
}
System.out.println();
}
}
public void N_back(int n,int nodes,int[][] tu){
if (nodes == n){
lists.add((ArrayList<Integer>) list.clone());
}else {
for(int i=0;i<n;i++){
if(tu[nodes][i] == 0){
/**
* 开始置1
*/
setOne(tu,nodes,i);
list.add(i);
N_back(n,nodes+1,tu);
list.remove(list.size()-1);
/**
* 开始清零
*/
clear(tu,nodes,i);
}
}
}
}
public void setOne(int [][] tu,int x,int y){
HashSet<String> set = new HashSet<>();
// 横向
for (int i = 0; i < tu.length; i++) {
// 通过加1来避免置1导致的将其他的节点的操作清空
tu[x][i]++;
set.add(x+""+i);
}
// 竖向
for (int i = 0; i < tu.length; i++) {
if(!set.contains(i+""+y)) {
tu[i][y]++;
set.add(i+""+y);
}
}
// 反斜
for(int i=0;i<tu.length;i++){
int x1 = i;
int y1 = y+x-x1;
if(!set.contains(x1+""+y1))
if(y1>=0&&y1<tu.length) {
tu[x1][y1]++;
set.add(x1+""+y1);
}
}
// 正斜
for (int i = 0; i < tu.length; i++) {
int y2 = i;
int x2 = y2-y+x;
if(!set.contains(x2+""+y2))
if(x2>=0&&x2<tu.length) {
tu[x2][y2]++;
set.add(x2+""+y2);
}
}
set.clear();
}
public void clear(int [][] tu,int x,int y){
HashSet<String> set = new HashSet<>();
for (int i = 0; i < tu.length; i++) {
tu[x][i]--;
set.add(x+""+i);
}
for (int i = 0; i < tu.length; i++) {
if (!set.contains(i+""+y)) {
tu[i][y]--;
set.add(i+""+y);
}
}
for(int i=0;i<tu.length;i++){
int x1 = i;
int y1 = y+x-x1;
if (!set.contains(x1+""+y1)) {
if (y1 >= 0 && y1 < tu.length) {
tu[x1][y1]--;
set.add(x1+""+y1);
}
}
}
for (int i = 0; i < tu.length; i++) {
int y2 = i;
int x2 = y2-y+x;
if (!set.contains(x2+""+y2)) {
if (x2 >= 0 && x2 < tu.length) {
tu[x2][y2]--;
set.add(x2+""+y2);
}
}
}
set.clear();
}
public static void main(String[] args) {
new n_皇后问题();
}
}
结果:
4皇后:
2
1 3 0 2
2 0 3 1
8皇后:
92
0 4 7 5 2 6 1 3
0 5 7 2 6 3 1 4
0 6 3 5 7 1 4 2
0 6 4 7 1 3 5 2
1 3 5 7 2 0 6 4
。。。。。。。。