终于理解了n皇后问题

借鉴:

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
。。。。。。。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值