Java由浅到深——递归学习N皇后问题

借鉴于———https://www.cnblogs.com/houkai/p/3480940.html

         国际西洋棋棋手马克斯·贝瑟尔于1848年提出:在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法?

          对于这个问题,我一开始首先想到是用二维数组来解决这个问题但是无奈不会。看了大神的代码,我感到收益匪浅。。向大神致敬!

好了,这个博客主要是解决大神代码一些较难懂的一些问题。闲话不多说上代码ing

首先,下面这段代码较容易理解,主要是用for循环一个一个的暴力解算,把所有的情况都存放到数组中然后在进行判断。

注释:大多自己总结。

package queen;
/*
 * 第一步:先用for暴力解算
 * 算法思路:主要是但看一个皇后问题的行或者列然后把行和列所有的可能性都存放在一个数组中。
 * 不分原因直接去一个一个的去试。一共计算8的8次方
 */
public class Queen_1{
	static boolean check_1(int n,int ...a) {
		//循环遍历后7行
		for(int i=2;i<=n;i++)
		{
			//循环遍历从1行到i行   看看是否有不符合条件的
		    for(int j=1;j<=i-1;j++)
		    {
		    	//比较一个数组中的不符合条件的返回 false  
		    	//判定条件是皇后不能在同一行  和同一斜线
		        if ((a[i]==a[j])||(Math.abs(a[i]-a[j])==i-j))		        
		        {
		            return false;
		        }
		    }
		    }
		return true;
	}
	public static void main(String[] args) {
		//定义一个数组,把皇后一个个的放进去这个数组中,之所以定义9个是因为循环的时候从1开始,便于代码的可读性
		  int []a=new int [9];
		    int count = 0;
		    for(a[1]=1;a[1]<=8;a[1]++)
		    {
		        for(a[2]=1;a[2]<=8;a[2]++)
		        {
		            for(a[3]=1;a[3]<=8;a[3]++)
		            {
		                for(a[4]=1;a[4]<=8;a[4]++)
		                {
		                    for(a[5]=1;a[5]<=8;a[5]++)
		                    {
		                        for(a[6]=1;a[6]<=8;a[6]++)
		                        {
		                            for(a[7]=1;a[7]<=8;a[7]++)
		                            {
		                                for(a[8]=1;a[8]<=8;a[8]++)
		                                {
		                                	//调用判断的算法如果是false这个数组就不是所要寻找的
		                                    if(!check_1(8,a))   
		                                        continue;
		                                    else
		                                    {
		                                        for(int i=1;i<=8;i++)  
		                                        {
		                                            System.out.print(a[i]+"  ");
		                                        }
		                                       System.out.println();
		                                        count++;
		                                    }
		                                }
		                            }
		                        }
		                    }
		                }
		            }

		        }
		    }
		    //输出一共有多少种情况。
		    System.out.println(count);
	}
}

为了让读者更好的理解回溯法意思,这一段代码更好的解释了什么是回溯法的意思↓

package queen;
/*
 * 第二步:中间穿插 if    continue简单的实现回溯法的一些基本思想
 * :和第一步的思想差不多就是  每一个步都要比较一次,这样可以及时发现不对,如果返回false就结束本轮循环,
 * 节省时间,提高的效率
 */
public class Queen_2 {
	static boolean check_2 (int a[],int n)
	{//多次被调用,只需一重循环   只需看前面的与本行有没有不符合条件的
	    for(int i=1;i<=n-1;i++)
	    {
	    	//判定条件是皇后不能在同一行  和同一斜线
	        if((Math.abs(a[i]-a[n])==n-i)||(a[i]==a[n]))
	            return false;
	    }      
	    return true;
	}
	public static void main(String[] args) {
		int []a=new int[9];
	    int count = 0;
	    for(a[1]=1;a[1]<=8;a[1]++)
	    {
	        for(a[2]=1;a[2]<=8;a[2]++)
	        {
	            if (!check_2(a,2))  continue;
	            for(a[3]=1;a[3]<=8;a[3]++)
	            {
	                if (!check_2(a,3))  continue;
	                for(a[4]=1;a[4]<=8;a[4]++)
	                {
	                    if (!check_2(a,4))  continue;
	                    for(a[5]=1;a[5]<=8;a[5]++)
	                    {
	                        if (!check_2(a,5))  continue;
	                        for(a[6]=1;a[6]<=8;a[6]++)
	                        {
	                            if (!check_2(a,6))  continue;
	                            for(a[7]=1;a[7]<=8;a[7]++)
	                            {
	                                if (!check_2(a,7))  continue;
	                                for(a[8]=1;a[8]<=8;a[8]++)
	                                {
	                                    if (!check_2(a,8))  
	                                        continue;
	                                    else
	                                    {
	                                        for(int i=1;i<=8;i++)  
	                                        {
	                                            System.out.print(a[i]+" ");
	                                        }
	                                       System.out.println();
	                                        count++;
	                                    }
	                                }
	                            }
	                        }
	                    }
	                }
	            }

	        }
	    }
	   System.out.println(count);
	}
}

理解完什么是回溯法,接下里就是用递归来实现上面的代码了,回溯法就是一行一行的比不行就回头在进行比较,而不是像第一个代码那样不分青红先遍历出来再说。

最后递归出来,原理和第二个一模一样

package queen;
public class Queen {
	static int a[] = new int [10];
	static int n=8,count=0;
	static int check_2 (int a[],int n){
		//多次被调用,只需一重循环   只需看前面的与本行有没有不符合条件的
	    for(int i=1;i<=n-1;i++){
	    	//判定条件是皇后不能在同一行  和同一斜线
	        if((Math.abs(a[i]-a[n])==n-i)||(a[i]==a[n]))
	            return 0;
	    }      
	    return 1;
	}
	static void backtrack(int k){
	    if (k>n){
	        for(int i=1;i<=8;i++){
	            System.out.print(a[i]+" ");
	        }
	        System.out.println();
	        count++;
	    }else{
	        for (int i = 1;i <=n; i++){
	            a[k] = i;
	            if (check_2(a,k) == 1)
	            {backtrack(k+1);}
	        }
	    }	       
	}
	public static void main(String[] args) {			
		    backtrack(1);
		    System.out.println(count);;
	}
}

 

总结:通过学习大神的代码,了解了回溯法递归的一些常用方法,更加了解了数组用法,不说了掉了几根头发了。。。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值