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

  • 相关阅读:
    PHP中使用cURL实现Get和Post请求的方法
    详解回调函数——以JS为例解读异步、回调和EventLoop
    JavaScript中变量提升------Hoisting
    js 变量提升(JavaScript Scoping and Hoisting)
    js 如何判断数据是数据还是对象
    Bootstrap Modal 垂直方向加滚动条
    Bootstrap Affix(附加导航(Affix)插件的用法)
    Vue 源码解析:深入响应式原理(上)
    ceph API之PHP的S3-SDK包的泛域名解析问题
    ceph API之PHP的客户端连接
  • 原文地址:https://www.cnblogs.com/yanyu01/p/8983107.html
Copyright © 2011-2022 走看看