欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-05-25 21:15:10
...

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

问题

在一个8*8的棋盘中,有八个皇后的棋子。这些棋子所放的位置的同一行,同一列和同一个斜线上不能出现另一个皇后,问有多少种摆放的方式。
八皇后问题(递归回溯法)

思路

(1)先将一个皇后放到第一行的第一列

(2)然后将第二个皇后放到第二行的第一列,进行判断是否与其他皇后冲突,如果冲突,则移动到第二列…以此类推,直到不再冲突,如果全部列都冲突,则去除该行,前一行在进行移动列,寻找下一个不冲突的位置。

(3)然后根据前两个步骤继续放第三行,第四行,直到第八行,当找到第八行合适位置的时候,则找到一种正确的摆放方式。

(4)去除第八行的皇后,移动第七行的皇后向后移动一列,直到找到下一个与前面不冲突的地方或者到最后一列,如果找到下一个不冲突的地方,就将第八行的皇后放入再一次寻找,就这样一次一次进行循环递归回溯。一次列推下去。

(5)这样往复的进行循环,就能找到全部的摆放方式

其实这样说,可能也有些人不太理解,尤其是在回溯这方面,下面我们先看一下代码,然后我会在对此进行详细的分析。

代码

在这我们通过一个一维数组 arr[8] arr的(下标)表示第几行arr[i]=val ,val表第i个皇后,放在i行的val+1列。【这里从0开始】
代码如下:

public class Queue8 {
	
	int max = 8; //定义行
	int[] arry = new int[max];//定义数组
	static int count =0;//定义解法的个数
	public static void main(String[] args) {
		Queue8 queue8 = new Queue8();
		queue8.check(0);
		System.out.println(count);
	}
	
	//编写一个方法,放置第n个皇后
	public void check(int n) {
		//如果以及摆放好
		if (n == max) {
			print();
			return;
		}
		//依次放入皇后。并判断是不是冲突
		for (int i = 0; i < arry.length; i++) {
			//将这个皇后放进第i列
			arry[n]=i;
			//判断冲突
			if (judge(n)) {
				//不冲突,就放入这个皇后
				check(n+1);
			}
			//如果冲突,就执行arry[n]=i,这样就相当于移动了一列
		}
	}
	
	//查看当前我们放置第n个皇后,就去检测该皇后和前面的是否冲突
	/**
	 * @param n :表示第几个皇后
	 * @return
	 * Math.abs():绝对值
	 */
	public boolean judge(int n) {
		for(int i=0;i<n;i++){
			//arry[i] == arry[n]表示n个皇后和前面的皇后是否在一列
			//Math.abs(n-i) == Math.abs(arry[n] - arry[i])表示判断第n个皇后和第i个皇后自爱一个斜线【行和列的差值是一样的】
			if (arry[i] == arry[n]||Math.abs(n-i) == Math.abs(arry[n] - arry[i])) {
				return false;
			}
		}
		return true;
	}
	
	//定义一个方法,将皇后摆放的位置输出
	public void print() {
		count++;
		for(int i =0;i<arry.length;i++){
			System.out.print(arry[i] + " ");
		}
		System.out.println();
	}
}

分析

我们对这段代码中最关键的部分进行了修改:

public void check(int n) {
    if (n == max) {
        print();
        return;
    }
    for (int i = 0; i < arry.length; i++) {
        System.out.println("这是"+n+"行,第"+i+"列");
        arry[n]=i;
        if (judge(n)) {
            check(n+1);
        }
    }
}

这样他在运行的时候,就会不断的输出第几行和第几列,这样我们通过debug的方式来探寻这是如何回溯的(请看下面这个图):
八皇后问题(递归回溯法)
我们可以发现当前4行都找到相应的皇后位置的时候,第5行的皇后这7列都不能使用,于是在n=5的时候就进行了一次回溯,我们可以发现在第5行之前,第4行是在第3列的,在回溯的时候,第4行将继续执行for循环,一次判断下面的列是否可行,终于在第7列的时候找到了,于是在递归运算第5行,回溯就是这样来的,这样可能还不是很清楚,下面,我们用图进行相应的展示:
首先把前4行放好:
八皇后问题(递归回溯法)
我们可以看出,第五行的所有的列都于前面的皇后冲突,因此执行到这一步就没有在递归,而是进行了回溯:

在回溯的过程中,先回溯到了第4行,继续执行check(4),继续执行for循环,于是第4行继续的向下一列移动,当移动到第7列的时候找到了相应的位置(不与前三个皇后冲突),但很可惜第5行依旧没有位置放皇后:
八皇后问题(递归回溯法)
于是将继续回溯,这一次第4行已经到头了,所以这次n=4开始回溯,回溯到第3行,继续执行check(3),于是第3列开始进行移动,找到相应的位置第6列,于是继续递归寻找第4行,找到了相应位置第1列,在此递归找第5行,找到了相应位置第3列

八皇后问题(递归回溯法)
这样前5行就成功的找到了,这样依次的向下不断的递归回溯,最终就会得到相应的位置,在对这些位置进行统计就得到了相应的个数。