n皇后问题:在NxN的棋盘上,讲n个皇后放置于其中,这里的皇后是国际象棋中的棋子皇后,众所周知皇后是可以走直线和斜线,而且走的格数是不定的,因此大家往棋盘上放置棋子时是需要进行三方面考虑的,其实本质上是4方面的考量,但是绝大多数的编码时或者是按行的方向或者是按照列的方向,所以我们实际需要考虑的只是剩下的列行几两条斜线方向而已,小甲鱼的介绍算法视频中曾经将一条斜线分为向上或者向下,其实本质上是一样的,这里采取的方式和小甲鱼视频中的方式不同,是采用了数学上的斜线代表式将其表示出来(这里要进行一些说明,在相关螺旋矩阵,不管是正向还是反向的,这种采用数学方式将行作为y轴,列作为x轴的方式都会有十分奇妙的效果),这方面下面会进行详细介绍。
递归,谈及这个词,读者们可能不会陌生,大家或多或少都有写过递归程序的经历,虽然递归程序的算法效率并不高,但是往往会使得程序变得异常的简单,所以现在一些编程规范里会能够用递归就用到递归,我在刷leetcode相关题的时候看相关参考书的时候就曾深有体会,一个递归会让程序更具有可读性,考虑到程序的这方面,我还是很推荐大家用递归算法的。闲话少说,我们进入正题,既然是要才用递归法去求解问题,那么问题来了,递归的终止条件来了,就像约瑟夫问题(爬楼梯问题)的终止条件一样,我们首先要知道的就是什么时候能够跳出,可能大家一会可能想不到,但是我说我是以行(row)的顺序进行处理问题,那么终止条件显而易见就是row等于n了,这里我接触的编程语言数组是从0开始,至于另一个重要的话题(何时开始递归,何时才能将一个问题简化为函数体的简化版本),至于这个问题,我们可能会发现,我们这里用到的递归可能会和我们以前写的递归有些许不太一样,因为问题的规模并没有缩小,而是一样的,这里的递归函数才用的是search()实现,之后会进行相关的实现
下面来说说我的算法的具体思路:
首先我一一个一维数组记录每个皇后的相关位置信息,有的读者有要问了,明明是个棋盘,为什么不是选择二维数组却去才用一维数组,如果我说我的才用方式是chess[row]=col,你是不是会豁然开朗,我们实际上要记录的本质上将只是每个皇后的列信息而已,因为我写程序是按行的顺序进行的,所有这样写更加简单,而且程序的效率更高,在许多要求复杂度的OJ平台上,这一点上是要斤斤计较的,考虑到输出结果的可观赏性将得到的数据填充入相关二维数组中,其中1表示位置上放置皇后,0则表示该位置空闲,这一点上仅凭个人喜好,有的读者还喜欢用*号表示纯在呢。
下面具体以八皇后为题为例解决上述问题,首先我们从0行到7行顺序进行搜寻相关位置,这里没一行到下一行我们才用递归函数search()实现,跳出条件是row==8的时候,同时row==8的时候我们将解法总数计数器进行自加,这里谈及个笑话,数学加高斯在这个问题上还犯过错,现在想来有计算机真好啊,row!=8时,首先要对我们取得位置进行判断,这里我运用的check()函数去实现,对于check(),我们上面已经讲过要对三方面进行排除,列和两条斜线,这一点上还真是要感谢数学上的解析几何,下面的代码注释中我会有详细的解释,这里就不再详述。相面就献上我的代码,那句话真心说的好,show me your code!!!
具体算法采用java语言实现:
package Recursion;
/**
* EightQueen
*@author:Mr.wang
*@version:1.0
*@time:2015/11/3
*/
public class EightQueen
{
static int[] col1 = {0,0,0,0,0,0,0,0};
static int sum = 0;
public static void main(String[] args)
{
search(0);
}
public static void search(int row)
{
if(row == 8)
{
sum++;
printMatrix();
}
for(int t = 0;t <= 7;t++)
{
if(check(row,t))
{
search(row+1);//开始进行递归
}
}
}
public static boolean check(int row,int col)//解决冲突函数
{
for(int k = 0;k <= row-1;k++)
{
if(col1[k]==col)//列冲突
{
return false;
}
if((col1[k]+k)==(row+col))//正斜线冲突解决,这里if中的判断条件其实质是该条直线的函数表达式,如果你将x,y引入就会显而易见的
{
return false;
}
if((col1[k]-k)==(col-row))//反斜线冲突解决,同上
{
return false;
}
}
col1[row] = col;//记录正确位置信息
return true;
}
public static void printMatrix()//填充矩阵,进行相关输出
{
int[][] chess = new int[8][8];
for(int i = 0; i <= 7;i++)
{
for(int j = 0;j <= 7;j++ )
{
chess[i][j] = 0;
}
}
System.out.println("第"+sum+"个结果矩阵为:");
for(int i = 0;i <= 7;i++)
{
chess[i][col1[i]] = 1;
}
for( int m = 0; m <= 7;m++)
for(int n = 0;n <= 7;n++)
{
System.out.print(chess[m][n]+" ");
if(n == 7)
System.out.println();
}
}
}