递归八皇后解法——个人理解,无优化

本文探讨了八皇后问题的解决方案,通过递归算法实现了在8x8的棋盘上放置八个皇后,确保任意两个皇后不位于同一行、列或对角线。文章详细分析了问题的特性,并提出了将数独思想应用于八皇后问题的创新方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

首先,缅怀数学王子——高斯,在没有计算机且图论相对不完善的时代,手动得出八皇后的76种解法。

学习了递归有两年多,没用递归做解决过八皇后的问题。今天,经过一番内心的挣扎,终于写出了这个问题的解法。


接下来进入正题:

问题:在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列且同一斜线上,问有多少种摆法。

分析问题:个人理解,看到问题,第一反应是画图,但是8*8的图有点大。于是简化问题,做2*2的图。

 

0.0

当将的第一个皇后(黑色代表皇后)放入棋盘,我就知道,此山不能容二虎。于是我们从3*3开始。

爱你呦

嗯,不出意外,3*3的图最多放两个。

4*4这里就不放图了,还是不行,只能放3个满足条件的皇后。

But当棋盘变为5*5时,就可以实现5个皇后不会攻击到彼此。

例图:(只是其中一种情况)

稍等

现在,我们回头再看问题。这个问题,有点像数独。嗯,数独中有一个规则是:同一个数字,一行一列只能出现一次。而八皇后问题也有条件:每个皇后所处的行列不能有其他的皇后。而这个八皇后多了一个条件:这个皇后所处的斜线上也不能幽皇后。这里提供一个思路:将数独中的数字可以完美转换成一个n*n矩阵的,而矩阵在进行列变化时,其行列的总和不变,也就是说,这个数独的本质没变,他还是数独,不会出现同一行或者同一类有相同的数字。将这一思想引入八皇后问题,我们是否可以先初始化一个满足一个不处于同一行、同一列的八皇后?这个条件很容易满足,如下图:

1

当所有皇后出现在对角时,就初始了皇后的位置,且满足所有不处于同一行、同一列。接下来我们只用进行列边换,以完成多个皇后出现在同一斜线上的问题。

接下来,当我们进行行类变换时就会发现,当行边换与列边换变换可以达到同样的效果:

当我们将初始情况进行x1<--->x2变化时与y1<--->y2效果一样。那么,我们就可以只进行一种边换来解决这个问题。

这样做,直接将二维问题转化为一维。

现在,我们将每个皇后打标记,标记的号码为他的初始行数(这里行数与列数相等)。则会出现(以为例五皇):12345。现在我们要解决的问题是,如何边换12345的顺序,使他再转化到棋盘中时,同一斜线没有多个皇后。

我们现分析,出现同一斜线的必要条件:回到二维棋盘,当且仅当两个棋子的形成的直线斜率为1或者-1时,在同一斜线时。也就是:x2-x1=y1-y2或者y2-y1。好了,分析到这,问题基本思路就解决了。

还有一个要说的是,这一串数字的(x,y)属性体现在哪里?

答:数字所处数字串的位置为y值,该处所对应的值为x值。(x,y是等价的,是可以互换的,但边换的过程中不能互换)

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

            个人思路,无优化,仅供参考。

我们可以用遍历树解决来解决这一问题:

5000

求解的过程类似于树的遍历,有多分枝的出口(递归中递的过程),每次在向下递的同时判断,这个操作是否可行。

而返回的路径只有一条就是上一层(递归中递的过程),及就是一个树节点可以有多个孩子,他的父节点只有一个。

这是递归的思想,再向其中加入判断,就可以完成不在同一斜线的可能。

代码如下:

package 实验;
public class eight_queens {
	static int X=0;//记录解法总数
	static int num;//定义皇后总数
	public static void main(String[] args) {
		num=5;
		int []Q=new int[num];//初始化棋盘(一维棋盘)
		E_Q(Q,num);
		System.out.println(X);//输出解法的总数
	}
	private static void E_Q(int arr[],int n) {//递归体
		if(n==0) {//出口
			for(int i=0;i<num;i++)
				System.out.print(arr[i]);//输出正确的序列(一维的棋盘)
			System.out.println();
			X++;
		}
		else if(n==num) {//第一位皇后进入时不需要判断
			for(int i=1;i<=num;i++) {
				arr[0]=i;
				E_Q(arr,n-1);
			}	
		}
		else {
			/*
			 *可以下行的条件:
			 *         1、该数字 该串没有isNoin
			 *         2、不在一条斜线上
			 */
			for(int i=1;i<=num;i++) {
				if(isNoin(arr,n,i)&&isYx(arr,n,i)) {
					arr[num-n]=i;
					E_Q(arr,n-1);
				}	
			}
		}
	}
	private static boolean isYx(int arr[],int n,int i) {//该数字是否与之前的重复
		int x1,y1,x2=num-n,y2=i;
		for(int j=0;j<=num-n-1;j++) {
			x1=j;y1=arr[j];
			if(x1-x2==y1-y2||x1-x2==y2-y1) return false;
		}
		return true;
	}
	private static boolean isNoin(int arr[],int n,int i) {//该数字是否与之前的在一行
		for(int j=0;j<num-n;j++)
			if(arr[j]==i)
				return false;
		return true;
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值