java回溯法(递归)解八皇后问题

问题描述:

八皇后问题,是一个古老而著名的问题,是回溯算法的典型例题。该问题是十九世纪著名的数学家高斯1850年提出:在8X8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。总共有92种。。。

问题分析:

我们先建立一个8*8的棋盘,在棋盘的第一行的任意位置安放第一个皇后。紧接着,在第二行可以放置的任意位置放第二个皇后。依次下去,直至每一行都有一个皇后结束。由于我们有找出所有的摆放情况,如果某一列上已放置过皇后,再放一个必定被吃掉,所以必须要回溯,将前面的皇后清掉,再重新放置。

放置约束条件

假设要在第r行第c列放置皇后,首先要判断相关的四条线(上下,左右,左下右上,左上右下)是否已放置过皇后。由于我们是按行序递增放的,因此不用判断每行放置两个的问题。我们分别用四个数组记录所有的线是否放过皇后,这样可以避免每次都遍历四条线。

java递归实现

import java.util.*;
public class EightQueen {
static int n = 8;// 每行(列)格式,也即皇后数
static int[] row = new int[n + 1];// 记录那些行放过皇后(row[0]不用)
static int[] col = new int[n + 1];// 记录那些列放过皇后(col[0]不用)
static int[] rowoblique = new int[2 * n];// 记录那些上对角线放过皇后(rowoblique[0]不用)
static int[] coloblique = new int[2 * n];// 记录那些下对角线放过皇后(coloblique[0]不用)
static List<int[]> store = new ArrayList<int[]>();// 保存所有摆放记录
/**
* 判断第r行第c列是否可放,如果可以则放皇后并置标志位返回true,反之返回false
* @param r
* @param c
* @return
*/
private static boolean setSign(int r, int c) {
if (col[c] == 0 && rowoblique[r + c - 1] == 0
&& coloblique[r - c + n] == 0) {
row[r] = c;
col[c] = 1;
rowoblique[r + c - 1] = 1;
coloblique[r - c + n] = 1;
return true;
} else {
return false;
}
}
/**
* 清除第r行第c列放置的皇后并复原标志位
* @param r
* @param c
*/
private static void clearSign(int r, int c) {
col[c] = 0;
rowoblique[r + c - 1] = 0;
coloblique[r - c + n] = 0;
}
/**
* 依次从第r行的每一列开始放置皇后,放置成功后递归调用r+1行
* @param r
*/
public static void countEightQueen(int r) {
if (r > n) {
store.add(row.clone());
return;
}
for (int i = 1; i <= n; i++) {
if (setSign(r, i)) {
countEightQueen(r + 1);
clearSign(r, i);
}
}
}


public static void main(String[] args) {
countEightQueen(1);//从第一行开始放置
//输出所有情况
for (int[] temp : store) {
for (int t = 1; t <= n; t++)
System.out.print(temp[t] + " ");
System.out.println();
}
//输出所有的放置数目
System.out.println(store.size());
}


}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值