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秒就是算法的大概极限了(这个也是在网上看到的),自己还是一个菜鸟,现在就是想一想。还是理解回溯的思想,在穷举的时候对于结果进行函数限制,方便后面的列举,大大加快算法的效率。

 

posted on 2018-05-02 23:10  丶烟雨丶  阅读(1738)  评论(0编辑  收藏  举报

导航