N皇后问题(递归回溯)

  今天讲了N后问题,现在来复习一下。

  N后问题就是在N*N格的棋盘上面放置彼此不受攻击的n个皇后。这里的皇后指的是国际象棋中的皇后,按照国际象棋的规则,皇后可以攻击当前行和当前列还有同一斜线的棋子。简单来说,就是n个皇后的位置不可以在同一行,同一列,同一斜线。因为这几天学习的是回溯算法,很简单的想到了回溯。这个问题也是经典的回溯算法习题之一。

  下面来想一下问题所包含的条件,明显的条件就是棋盘是n*n,而且很简单就想到n个皇后不可以在同一列,就是每一列都会有一个皇后。下面就是隐式的条件了,同一行和同一列都可以很简单的解决,同一斜线不是很好想。后来发现同一斜线的皇后都是皇后的位置差和皇后所在的列相等。就是皇后的位置斜率为1。翻译为代码语言就是,皇后所在的位置的差的绝对值等于皇后的列的差的绝对值。这个后面还会讲一下。条件都讲完了,下面就说一说算法的主体。

  算法的主体是由递归构成,递归的参数就是当前考虑的皇后的列,为了下面的计算方便,这里将皇后的个数和数组都传了进去。为什么传进去数组?因为自己一开始想的是一个二维数组,这个也是大家容易想到的,但是后来发现,解的形式和数组的下标有关,干脆将二维数组变为了一维数组,将皇后所在的列变为数组的下标。这样,就省去了很多的无用功。递归的边界就是k的位置大于等于n。递归的主体是一个for循环,将循环的值赋值给数组当前的位置,同时检验当前位置是否正确,如果正确就进行下一个递归(k的值加一),不正确就进行下一次循环。讲到了检验k的位置,就说一说这个方法,很简单,就是判断当前位置是不是符合问题的条件,要有一个返回值,方便后面的调用。检验的时候也是要用到for循环。

  算法的主体讲完了,下面就直接粘贴代码,代码如下:

package sf;

import java.util.Scanner;

//N后问题
public class demo7
{
	public static int num=0;//累加和
	//判断当前位置是否正确
	public static Boolean judge(int[] p,int k)
	{
		for(int i=0;i<k;i++)
		{
			//绝对值的判定和列的判定。(不用判定行)
			if((Math.abs(i-k)==Math.abs(p[i]-p[k]))||(p[i]==p[k])) {
				return false;
			}
		}
	  //要注意这个return的位置,在这里是为了让for循环能够一直循环下去,不被中间的位置打断,可以将
	  //这个return放到for循环中体验一下。会发现,解的个数会变多。
	  return true;
	}
	//算法主体  递归回溯 k为当前考虑位置
	public static void Queen(int[] p,int n,int k)
	{
		//这里的方法主体还是要多想一想
		if(k>=n)
		{
			num++;
			//打印结果
			for(int i=0;i<n;i++)
				System.out.print(p[i]);
			System.out.println("");
		}else{
			for(int j=1;j<=n;j++)
			{
				//System.out.println(k);
				//将皇后的位置赋值给数组中的元素,相当于放置皇后
				p[k]=j;
				if(judge(p, k))
				{
					//递归下一个位置
					Queen(p, n, k+1);
				}
			}
		}
	}
	public static void main(String[] args)
	{
		System.out.println("请输入皇后的个数:");
		Scanner sc=new Scanner(System.in);
		int n=sc.nextInt();
		int []p=new int[n];
		Queen(p,n,0);
		//将结果打印出来,如果只是打印这一个计数,程序的运行会快一点。
		System.out.println(n+"皇后问题的解共:"+num+"种");
	}

}

  算法的代码就是这样,算法的主体还是不好想的,我想了一会,感觉还是存在着一些问题,但是代码执行的结果正确,就不在想了。要注意算法中的for循环的指针的大小,这里还是要想一想的,虽然只有简单的一维数组。下面就讲一讲自己的一些想法,这个算法就是简单的递归求解,说的明白一点,就是穷举法,这就是这个算法的不足之处。只是在简单的列举之后,并没有进行函数限制。这个和回溯的思想有些不一样,回溯的思想是算法的主体还要有函数限制,将后面的解的一些错误的子树直接去掉,这个算法没有做到这一步,算法的实现还是有很大的提升空间,大概在求16皇后问题的时候需要100秒就是算法的大概极限了(这个也是在网上看到的),自己还是一个菜鸟,现在就是想一想。还是理解回溯的思想,在穷举的时候对于结果进行函数限制,方便后面的列举,大大加快算法的效率。

原文地址:https://www.cnblogs.com/yanyu01/p/8983107.html

时间: 2024-11-10 21:17:55

N皇后问题(递归回溯)的相关文章

八皇后问题——递归+回溯法

八皇后问题,是一个古老而著名的问题,是回溯算法的典型案例.该问题是国际西洋棋棋手马克斯·贝瑟尔于1848年提出:在8X8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行.同一列或同一斜线上,问有多少种摆法. 高斯认为有76种方案.1854年在柏林的象棋杂志上不同的作者发表了40种不同的解,后来有人用图论的方法解出92种结果. 求解过程: 采用遍历的办法,就是采用将每种情况都验证的办法最终找出问题的解,但是蛮力遍历的话,需要遍历的数据量太大,计算时间花费太大,所以在遍历

N皇后问题--递归回溯

著名的N皇后问题,就是先按照行一行一行的找,先找第一行,第一行找到一列能满足条件,继续找下一行,如果下一行也找到一列能满足条件,继续找下一行,一次类推,最终找到解, 但是,如果找不到的话, 就说明上一行放的位置错误, 所以回溯到上一行中,继续找下一列,如果找不到,继续回溯,大体就是这么执行找到解的. 下面是代码: 1 #include <stdio.h> 2 3 const int MAX = 30; 4 int n; 5 int a[MAX];//保存当前列值 6 int vis1[MAX]

通过C语言,利用递归回溯的方法,实现八皇后问题的求解

八皇后问题: 在国际象棋8*8的棋盘上,摆放八个皇后且皇后都无法吃掉对方,而八皇后的攻击路线 为它所在的列和行,还有45度斜线. 对于该问题,首先要确定递归的输入和输出,以及终止条件和方法.一个递归完成对当 前行皇后位置的确定,并通过遍历所有列,查找出所有可能.其中,利用对列的遍历实 现回溯. 具体实现方法,可以通过代码理解,以及思路参考https://blog.csdn.net/a304672343/article/details/8029122 参考博客的博主对于八皇后位置的表示处理的很好,

【八皇后问题】 回溯算法

回溯算法:回溯算法实际上是一个类似枚举的搜索尝试方法,它的思想是在搜索尝试中寻找问题的解,当发现不满足求解条件时,就“回溯”返回,尝试别的路径.之前介绍的基础算法中的贪婪算法,动态规划等都具有“无后效性”,也就是在分段处理问题时,某状态一旦确定,将不再改变.而多数问题很难找到"无后效性”的阶段划分和相应决策,而是通过深入搜索尝试和回溯操作完成的. 八皇后问题:8*8的国际象棋棋盘中放八个皇后,是任意两个皇后不能互相吃掉.规则:皇后能吃掉同一行,同一列,同一对角线的任意棋子. 模型建立:不妨设八个

八皇后问题(回溯法&amp;枚举法)

作者 : 卿笃军 本文讨论了八皇后问题的三种解决方案: 一.枚举法 二.回溯法(递归版) 三.回溯法(非递归版) 本来这些代码是以前编写好的,没有发表,由于最近又学习到了八皇后问题,自己整理了一下发表了出来! 首先.说明一下何为八皇后问题,我也不去谷歌了,直接简单的说明一下: 八皇后问题,就是在一个8*8的平面棋盘上,要求你摆放8个棋子,要求:这8个棋子不能有2个在同一行,也不能有2个在同一列,同时一条斜线上面也不能有2个~~~~ 比如:4*4的棋盘,你可以这样摆放(4皇后问题): 以上图为参照

八皇后问题的回溯和递归方法

1.回溯法 用一维数组记录皇后的位置.数组的下标代表皇后所处的行,下标对应的值代表皇后所处的列.用count记录皇后的个数,当count小于queen数时,在循环体中寻找合适位置的queen.寻找queen:从列1依次寻找,满足条件则count+1,继续从列1处寻找下一个queen.如全部找完没找到合适的位置,则count-1,从第count个皇后所在列的下一位置开始继续循环. public class Queen { public void queenInstance(int num ) {

[LeetCode系列]N皇后问题递归解法 -- 位操作方式

N皇后问题: 给定8*8棋盘, 放置n个皇后, 使其互相不能攻击(即2个皇后不能放在同一行/列/正反对角线上), 求解共有多少种放置方式? 这个问题的解答网上有不少, 但是位操作解法的我看到的不多. 下面贴出代码和图解, 也就不赘述了. 1 class Solution { 2 public: 3 /* 使用位操作实现的回溯算法. 按行扫描, 检测可以放置的列. 4 * 'limit' - 都是 '1'. 代表着所有列都被占据了 5 * 'h' - 是目前所有皇后列在行上的垂直投影. 如果 h=

HDU 2553 N皇后问题 --- 经典回溯

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=2553 DFS+回溯 /* HDU 2553 N皇后问题 --- 经典回溯 */ #include <cstdio> #include <cstring> const int maxn = 15; int cnt, n; bool visit[3][maxn*2];//3个数组分别标记列,y+x斜线,y-x斜线是否冲突 注意要*2 /* 从第r行开始满足条件地放置皇后 r表示行(从0开

POJ 2488 A Knight&#39;s Journey 递归回溯题解

简单的递归回溯法,锻炼基本的编程能力. 这类题是对代码能力的要求比对思想的要求高点. 而且要审题,题目要求安lexicographically 顺序输出,不小心递归的顺序就会输出错误了. 棋盘是由数字列或者行,和字母列或者行组成的,故此输出结果要注意. 个人觉得我的递归回溯写法是非常清晰, 工整的,O(∩_∩)O哈哈~ #include <stdio.h> #include <string.h> const int MAX_N = 27; bool board[MAX_N][MAX