记录【八皇后问题】解法过程,实现n皇后

八皇后问题:有一个八行八列的棋盘,有八个皇后棋子,这八个棋子摆在这八行八列的棋盘上。
而且八个皇后中的任意两个不能处于同一行、同一列,或同一斜线上。

本文地址:https://blog.csdn.net/kaeles/article/details/84933931

  • 通过问题我们可以看出,在棋盘上每行每列只能有且只有一个皇后。
  • 假如第一颗棋子落在(0,i)点上,那么第二行的棋子落在(1,j)点,其中 j≠i & j≠i-1 & j≠i+1,共有5或6中方法。以此类推。
  • 其中第一颗棋子共有8中落点。

解:

  • 1、把棋盘放进8*8的二位数组中。
  • 2、遍历当前行所有的列,取出点
  • 2、判断当前点是否可以落棋子
  • 3、如若可落子,回到第2步(通过递归),判断下一行
  • 4、所有行都已落子,记录解法并返回。
  • 5、继续通过第2步获取下一个点,继续往下执行直到所有列遍历完
private int size = 8;	//棋盘行列
private int[][] checkerboard ;//首先把棋盘初始化出来,此处代码:略

private void QueensSolving(int row = 0){
	if(row >= size){
		AddSolving();//添加当前的解到列表中
		return;
	}
	for(int col = 0 ; col < size ; col++){
		if( Check(row , col) ){
			checkerboard[row][col] = 1;
			QueensSolving( row + 1 );
			checkerboard[row][col] = 0;//避免递归时出现藏数据,
		}
	}
}

private bool Check(int row, int col){
	for(int i = 0 , i < size ; i++){
		if (queens[qx][i] == 1) return false;//当前行
		if (queens[i][qy] == 1) return false;//当前列
		
		//上半部分两边斜角
		if (qx - i >= 0) {
			if (qy - i >= 0 && queens[qx - i][qy - i] == 1) return false;
			if (qy + i < 8 && queens[qx - i][qy + i] == 1) return false;
		}
		//下半部分两边斜角
		if (qx + i < 8) {
			if (qy - i >= 0 && queens[qx + i][qy - i] == 1) return false;
			if (qy + i < 8 && queens[qx + i][qy + i] == 1) return false;
		}
	}
}

修改1

  • QueensSolving(int row = 0)中的列学循环也改成递归方式
private void QueensSolving(int row = 0, int col = 0){
	if(col >= size) return;
	if(row >= size){
		AddSolving();//添加当前的解到列表中
		return;
	}
	if( Check(row , col) ){
		checkerboard[row][col] = 1;
		QueensSolving( row + 1 );	//col从0开始递归,
		checkerboard[row][col] = 0;//避免递归时出现藏数据,
	}
	QueensSolving( row ,col+1 );
}

优化1

检测函数Check(int row, int col)是用时的消耗大户,在此去掉不必要的判断。

  • 1、每行某点通过检测后,会进行落子并前往下一行,所以每仅进且只有一个皇后
  • 2、落子是从低位依次往高位,所以当前点是当前解法中出现的最大点,当前解法出现的皇后都比该点低。

通过上面两点,可修改检测函数为:

private bool Check(int row, int col){
	for(int i = 0 , i < row; i++){
		if (queens[i][col] == 1) return false;//当前列
		if (col- i >= 0 && queens[row- i][col- i] == 1) return false;//左斜角
		if (col+ i < 8 && queens[row- i][col+ i] == 1) return false;//右斜角
	}
}

优化2

  • 因为每行有且仅有一个皇后,前文中也是以每行为单位进行计算的,那么把二位数组,改成一维数组,每个元素储存的为当前行皇后所在的列。
  • 因为行、列都是已0开始,那么把一维数组初始值设为-1;
  • Check(int row, int col)通过取斜边上的点与该点所在行上皇后的点对比
private int[] checkerboard = new int[size];
private void QueensSolving(int row = 0, int col = 0){
	if(col >= size) return;
	if(row >= size){
		AddSolving();//添加当前的解到列表中
		return;
	}
	if( Check(row , col) ){
		checkerboard[row] = col;
		QueensSolving( row + 1 );	//col从0开始递归,
		checkerboard[row] = -1;//避免递归时出现藏数据,
	}
	QueensSolving( row ,col+1 );
}
private bool Check(int row, int col){
	for(int i = 0 , i <= row; i++){
		if ( queens[ i ] == col ) return false;//当前列
		if ( queens[ row - i ] == col - i ) return false;//左斜角
		if ( queens[ row - i ] == col + i ) return false; //右斜角
	}
}
  • 需要注意以下 i <= row,不然的话计算不到第0行的数据

修改2

  • 因为斜边围城的是一个正四边形,所以行之间的差和列之间的差是相同的,例如(2,3)和(5,6),两点同在同一条斜边上,5-2=6-3。
  • Check(int row, int col)也可通过行与行,列与列的差值对比
private bool Check(int row, int col){
	for(int i = 0 , i < row; i++){
		if ( queens[ i ] == col ) return false;//当前列
		if ( queens[ i ] - col == row - i ) return false;//左斜角
		if ( queens[ i ] - col == i - row ) return false; //右斜角
	}
}
  • 修改后,一维数组便可不需要设置初始值。
  • 此处最好不要用Math.Abs() 太浪费,消耗的时间是普通运算的几十倍

返回顶部
返回博客列表

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值