N皇后问题利用回溯法求解

package queen;

import java.util.Arrays;

/**
 * n皇后问题
 * 在一个nxn的表格中,放n个皇后,要求没个皇后之间不能位于同一列,同一行,同一对角线上。
 * 求解思路:最容易想到的方法就是有序地从第 1 列的第 1 行开始,尝试放上一个皇后,
 * 然后再尝试第 2 列的第几行能够放上一个皇后,如果第 2 列也放置成功,
 * 那么就继续放置第 3 列,如果此时第 3 列没有一行可以放置一个皇后,说明目前为止的尝试是无效的(即不可能得到最终解),
 * 那么此时就应该回溯到上一步(即第 2 步),
 * 将上一步(第 2 步)所放置的皇后的位置再重新取走放在另一个符合要求的地方…如此尝试性地遍历加上回溯,
 * 就可以慢慢地逼近最终解了。*/
public class Queen {
	private  int n=0;//解的个数
	private int number;//皇后个数
	private int []location;//表示么行么个位置有皇后,如location[1]=2代表第二行第三个位置有皇后
	
	public Queen(int number){
		this.number=number;
		location=new int[number];
	}
	
	/**
	 * 判断第row行的第lacationNum位置能不能放皇后,
	 * 如果能,则返回true
	 * 否则 返回false
	 * */
	public boolean isCanPutQueen(int row,int locationNum){
		//如果是放在第一行,则随便放
		if(row==0){
			return true;
		}
		//经过分析,两个皇后满足规则的前提:列不能相同,行不能相同,并且行坐标只差等于纵坐标只差的绝对值,
		//由于我已定位每行放一个皇后,则“行不能相同”这个条件可以忽略
		for(int i=0;i<row;i++){
			int a=row-i;//行坐标之差
			int b=locationNum-location[i];
			if((a==Math.abs(b))||(b==0)){
				return false;
			}
			
		}
		//否则返回true
		return true;
	}
 
	
	// 放皇后
	public void putQueen(){
		 int row=0;//当前行
		 int col=0;//当前列
		 while(row>=0){
			 //遍历改行的列
			 for(int j=col;j<number;j++){
				 if((row==(number-1))&&isCanPutQueen(row, j)){
					  	//如果最后一行可以放,
						 location[row]=j;//保存该皇后的位置
						 print();//打印数组
						 n++;//保存解的个数
						 //回退,看还有没有其他的解
						 location[row]=0;//把最后一行的皇后位置清空
						 col=location[--row];//获取倒数第二行皇后的位置
						 if(col==(number-1)){//如果倒数第二行皇后位于最后,则还要倒退一行
							 if(row==0){//如果回退到的行为第一行,则代表改行的皇后位于最后,即没有解了,无法在回退
								 row--;//此时row为-1;则会结束while循环
								 break;
							 }
							 location[row]=0;//清空倒数第二行皇后位置
							 col=location[--row];//在倒退一行,并获取倒退后该行皇后的位置
							 col++;
							 break;//结束循环,
						 }else{//否则,直接清空倒数第二行皇后
							 location[row]=0;
							 col++;//并试着吧皇后放在刚行的下个位子
							 break;
						 }
					 
				 }
				 
				 if((j==(number-1))&&(!isCanPutQueen(row, j))){//如果改行每个位置都不满足,则倒退一行
					 col=location[--row];//获取倒退后该行的皇后位置
					 if(col==(number-1)){//如果该皇后位于末尾
						 if(row==0){//并且改行是第一行,则表示没有了更多的解
							 row--;//此时row为-1;则会结束while循环
							 break;
						 }else{
							 location[row]=0;//清空该皇后位置
							 col=location[--row];//在倒退一行
							 location[row]=0;//清空该皇后位置
							 col++;//并把该皇后放在下一个位子
							 break;
						 }
					 }else{
						 location[row]=0;//清空该皇后位置
						 col++;//并把该皇后放在下一个位子
						 break;
					 }
				 }
				 if(isCanPutQueen(row, j)){//如果可以放皇后,则继续放下一行
					 location[row]=j;//保存该皇后位置
					 row++;
					 col=0;//下一个皇后从下一行的第0个位置放起
					 break;
				 }
			 }
		 }
		 
	}

	
	//打印数组
	public void print(){
		System.out.println(Arrays.toString(location));
	}
	
	//获取解的个数
	public int getN(){
		return n;
	}

}
package queen;

import java.util.Arrays;

public class QueenDemo {
	public static void main(String[] args) {
		Queen q=new Queen(8);
		q.putQueen();
		System.out.println("解的个数为:"+q.getN());
 }
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值