八皇后-韩顺平java

韩顺平java P227

最近跟着老韩学java,学到P227集的时候老韩留了个八皇后问题,视频最后说以后会讲解这个问题,然后我找了一遍都没找到。这里给小伙伴分享一下我学习后的八皇后问题解法。

问题描述

不过多赘述,大家可以看老韩的视频。

老韩思路

在这里插入图片描述

思路解读

棋盘为八行八列,要放置八个皇后,且任意两个皇后都不能处于同一行、同一列或同一斜线。那就意味着每一行都要放置一个皇后。我们先在第一行放置皇后,再在第二行放置皇后,并且要检查与第一行的皇后是否冲突。如果不冲突,继续在第三行放置皇后,并且要分别检查是否与第一行和第二行的皇后冲突… …,直到在第八行放置皇后,并且要检查是否与前1-7行的皇后冲突。如果不冲突,则得到一种答案。

如何用arr[8]表示一种摆法

一维数组arr[8]共有8个元素,下标索引0、1、2、…、7分别表示棋盘的第1、2、3、…、8行。该索引对应的值表示棋盘对应的列。例如arr[0] = 0,表示第 1 个皇后放在棋盘的第 1 行的第 1 列;arr[1] = 4 表示第 2 个皇后放在棋盘的第 2 行的第列 5 列。所以图中的 arr[8] = {0, 4, 7, 5, 2, 6, 1, 3} 能表示一种摆法。

如何使用递归解决八皇后问题

使用递归解决该问题的关键:

1. 找到递归终止条件

我们从第 1 行开始放置皇后,每一行放置成功后,才能进行下一行的放置,如果我们成功的放置完八个皇后,我们就终止一次递归。
继续递归的条件:上一行放置成功。如代码段中的 judge 函数,上一行放置成功,judge返回true,继续迭代。

else中的for循环表示:index初始值为0,即第 1 行,遍历1 ~ 8列。如果放置成功,进入下一行(index+1),再次遍历1 ~ 8列。直至遍历完所有可能的结果。

if(index == 8) { // 退出条件:index能增加到8

	// 可输出数组看看
	for(int i = 0; i < 8; i++) {
		System.out.print(arr[i] + " ");
	}
	System.out.println();
	count++;

} else {  // 递归
	for(int i = 0; i < 8; i++) {  // 8 列
		arr[index] = i;  // index行,i列
		if(judge(index)) {  // 如果该行皇后放置成功,则可以递归进入下一行进行放置,直至到达退出条件
			check(index + 1);
		}
	}
}

2. 如何判断每一行是否放置成功

我们每行放置一个皇后,就已经避免了任意两个皇后在同一行,只需要用代码实现判断是否在同一列或同一条斜线。传入的参数 index 为当前正在放置的行,必须与前面的0 ~ index-1 行都不冲突。

  1. 在同一列时:
    arr[index] == arr[i]
  2. 在同一条斜线时:
    Math.abs(index - i) == Math.abs(arr[index] - arr[i])
    (相当于斜率为 1 或 -1)

代码如下:

// 判断该皇后是否与之前的皇后冲突
public boolean judge(int index) {

	for(int i = 0; i < index; i++) {
		if(arr[index] == arr[i] || Math.abs(index - i) == Math.abs(arr[index] - arr[i])) {
			return false;
		} 
	}
	return true;
}

完整代码

由于老韩是在 方法的递归调用 中将的这个问题,所以我的代码承袭了老韩当时的风格,建了一个名为 T 的类。(手动狗头)

public class EightQueen {

	public static void main(String[] args) {

		
		int count = 0;
		T t = new T();
		count = t.check(0);

		System.out.println("八皇后解法有:" + count + " 种");

	}
}


class T {

	int[] arr = new int[8];
	int count = 0;

	public int check(int index) {  // 从0行开始

		if(index == 8) { // 退出条件:index能增加到8

			// 可输出数组看看
			for(int i = 0; i < 8; i++) {
				System.out.print(arr[i] + " ");
			}
			System.out.println();
			count++;

		} else {  // 递归
			for(int i = 0; i < 8; i++) {  // 8 列
				arr[index] = i;  // index行,i列
				if(judge(index)) {  // 如果该行皇后放置成功,则可以递归进入下一行进行放置,直至到达退出条件
					check(index + 1);
				}
			}
		}

		return count;
	}

	// 判断该皇后是否与之前的皇后冲突
	public boolean judge(int index) {

		for(int i = 0; i < index; i++) {
			if(arr[index] == arr[i] || Math.abs(index - i) == Math.abs(arr[index] - arr[i])) {
				return false;
			} 
		}
		return true;
	}
}

public boolean judge(int index) {

	for(int i = 0; i < index; i++) {
		if(arr[index] == arr[i] || Math.abs(index - i) == Math.abs(arr[index] - arr[i])) {
			return false;
		} 
	}
	return true;
}

有疑问欢迎评论区留言!

如果觉得我讲的不清楚,可参考以下链接:
https://www.bilibili.com/video/BV1Yf4y1Q7kJ

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值