使用回溯法解决八皇后问题(同样适用于N皇后)。

在学习数据结构的时候,看到了一道八皇后的问题。写完后,再去网上查看发现原来这个问题有这么多的优化解法,相比之下相形见绌。但我还是记录下来,有兴趣的小伙伴可以看看。
先大致说下我的思路
创建一个初始化值为0的8x8的数组,0代表无皇后且不在其他皇后的攻击范围,-1代表皇后的位置,>0的整数代表格子在皇后的攻击范围。例如某个格子的数字为3说明该格子在3个皇后的攻击范围。
当遍历到二维数组的某个位置值为0,说明该位置安全,即可放置皇后,把皇后的位置设置为-1,并把该位置的竖,横,斜方向的格子全都+1,然后就直接跳到下一行继续查找合适的位置放置下一个皇后。假如该行查找完后并没有合适的位置,这时候就会回溯上一行,先把上一行当前皇后位置设置为0,并把该位置的竖,横,斜方向的格子全都-1,继续往右边格子遍历…以此类推。
下面是代码,最后求出8皇后一共有92种可能(没排除对称)
同样适用于求N皇后。

import java.util.ArrayList;
import java.util.List;

/**
 * 八皇后问题(N皇后问题)
 */
public class EightQueens {

    private static List<int[][]> list = new ArrayList<int[][]>();

    private static int[][] checkerboard;

    /** N代表皇后个数 */
    private static int N;

    public void judge(int i, int j) {
        if(checkerboard[i][j] != 0) {
            checkerboard[i][j]++;
        } else {
            checkerboard[i][j] = 1;
        }
    }

    /**
     * 把原来该格子所在的皇后标识和攻击范围去除。
     */
    public void toBack(int i, int m) {
        for(int j = 0; j < N; j++) {
            checkerboard[m][j]--;
            checkerboard[j][i]--;
        }
        for(int x = i, y = m; x >=0 && y < N; x--, y++) {
            checkerboard[y][x]--;
        }
        for(int x = i, y = m; x < N && y < N; x++, y++) {
            checkerboard[y][x]--;
        }
        for(int x = i, y = m; x < N && y >= 0; x++, y--) {
            checkerboard[y][x]--;
        }
        for(int x = i, y = m; x >= 0 && y >= 0; x--, y--) {
            checkerboard[y][x]--;
        }
        checkerboard[m][i] = 0;
    }

    public boolean search(int m) {
        for(int i = 0; i < N; i++) {
            if(checkerboard[m][i] == 0) {

                //在二位数组中把攻击范围和皇后位置加上标识
                for(int j = 0; j < N; j++) {
                    judge(m, j);
                    judge(j, i);
                }
                for(int x = i, y = m; x >=0 && y < N; x--, y++) {
                    judge(y, x);
                }
                for(int x = i, y = m; x < N && y < N; x++, y++) {
                    judge(y, x);
                }
                for(int x = i, y = m; x < N && y >= 0; x++, y--) {
                    judge(y, x);
                }
                for(int x = i, y = m; x >= 0 && y >= 0; x--, y--) {
                    judge(y, x);
                }
                checkerboard[m][i] = -1;

                //当m>=N说明一种情况完成,继续判断下一种情况
                if(++m >= N) {
                    //输出该可能的皇后位置排列
                    /*
                    System.out.println("num: " + list.size() + "--------------------------");
                    for(int x = 0; x < N; x++) {
                        for(int y = 0; y < N; y++) {
                            if(checkerboard[x][y] < 0) {
                                System.out.print("1 ");
                            } else {
                                System.out.print("0 ");
                            }
                        }
                        System.out.println();
                    }
                    */
                    list.add(checkerboard);
                    //把当前位置的皇后标识和攻击范围去除
                    toBack(i, --m);
                    //继续下一格
                    continue;
                }

                //递归往下层走
                if(!search(m)) {
                    //回溯
                    toBack(i, --m);
                } else {
                    return true;
                }
            }
        }
        return false;
    }

    public static void main(String[] args) {
        EightQueens eightQueens = new EightQueens();
        for(int i = 1; i <= 14; i++) {
            N = i;
            checkerboard = new int[i][i];
            eightQueens.search(0);
            System.out.println(i + "皇后一共有" + list.size() + "种可能");
            list.clear();
        }

    }
}

还有更好的解法
运用一维数组解决N皇后问题
使用回溯法和子集树(降维法)解决N皇后问题

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值