概念

回溯算法也叫试探法,它是一种系统地搜索问题的解的方法。回溯算法的基本思想是:从一条路往前走,能进则进,不能进则退回来,换一条路再试。


八皇后问题

国际西洋棋棋手马克斯·贝瑟尔于1848年提出:在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。高斯认为有76种方案。1854年在柏林的象棋杂志上不同的作者发表了40种不同的解,后来有人用图论的方法解出92种结果。计算机发明后,有多种计算机语言可以解决此问题。


基本思想

八皇后问题就是回溯算法的典型,第一步按照顺序放一个皇后,然后第二步符合要求放第2个皇后,如果没有位置符合要求,那么就要改变第一个皇后的位置,重新放第2个皇后的位置,直到找到符合条件的位置就可以了。


分析

为了分析简捷,以4皇后为例:

首先利用回溯算法,先给第一个皇后安排位置,如下图所示,安排在(1,1)然后给第二个皇后安排位置,可知(2,1),(2,2)都会产生冲突,因此可以安排在(2,3),然后安排第三个皇后,在第三行没有合适的位置,因此回溯到第二个皇后,重新安排第二个皇后的位置,安排到(2,4),然后安排第三个皇后到(3,2),安排第四个皇后有冲突,因此要回溯到第三个皇后,可知第三个皇后也就仅此一个位置,无处可改,故继续向上回溯到第二个皇后,也没有位置可更改,因此回溯到第一个皇后,更改第一个皇后的位置,继续上面的做法,直至找到所有皇后的位置,如下图所示。

java回溯算法解决n皇后问题 回溯算法八皇后_回溯算法

这里为什么我们用4皇后做例子呢?因为3皇后是无解的。

代码

首先,伪代码

//寻找当前行的皇后应该位于哪一列
void FindQueen(row)
{
  for(int i=0;i<8;i++)
  {
    //1.判断当前是否满足要求
    if(Is_Meet(row,i))
    {
    //2.判断当前是否是最后一行了
      if(最后一行){输出操作,并返回}
    //3.执行下一行匹配
      FindQueen(row+1);
    //4.如果进行到这一步,说明步骤三已经操作完,没有合适结果,需要返回上一步,即执行当前for的下一个循环
    }
  }
}



具体实现:

public class EightQueen {
	private int queen[] = {-1,-1,-1,-1,-1,-1,-1,-1};
	int total = 0;
	
	
	/**
	 * 判断是否冲突
	 * @param row
	 * @param column
	 * @return false 冲突 true 无冲突
	 */
	public boolean isMeet(int row, int column){
		int c;
		for(int r=0; r<row; r++){
			c = queen[r];
			/*同一行*/
			if(column == c)
				return false;
			/*正对角线*/
			if((row + column) == (c + r))
				return false;
			/*反对角线*/
			if((column - row) == (c - r))
				return false;
		}
		
		return true;
	}
	
	/**
	 * 在棋盘上摆放皇后
	 * 通过递归(堆栈原理)实现的回溯
	 * @param row
	 */
	public void findQueen(int row){
		for(int c=0; c<8; c++){
			if(isMeet(row, c)){
				queen[row] = c;
				if(row == 7){
					total++;
					display();
					return;
				}
				/*递归,放置下一枚皇后*/
				findQueen(row + 1);
			}
			/*发生冲突的情况,没有符合条件的结果,需要查看for的下一个循环,
			 * 如果循环结束仍然没有符合的条件,则返回上一步-回溯
			 */
			queen[row] = -1;
		}
	}
	
	public void display(){
		for(int i=0; i<8; i++){
			int inner;
			for(inner=0; inner<queen[i]; inner++)
				System.out.print("0");
				System.out.print("#");
			for(inner=queen[i]+1; inner<8; inner++)
				System.out.print("0");
			System.out.print("\n");
			
		}
		System.out.println("==========================");
	}
	
	public int getTotal(){
		return total;
	}
	
	public static void main(String[] args){
		EightQueen eightQueen = new EightQueen();
		eightQueen.findQueen(0);
		int total = eightQueen.getTotal();
		System.out.println("total is --> " + total);
	}
}

==========================================================================

二、循环解法

/**
 * @author         
 * @version        V1.0  
 * @Date           2018年1月30日 上午9:00:10 
 * @Email
 * @Description:   八皇后
 * 这是按列逐行循环的方法,不是回溯的方法,貌似更简单一些
 */

public class EightQueen {
	public static int num = 0;  //累计方案总数
	public static final int MAX_QUEEN = 8; //皇后个数
	/* cols[col] = row 表示第 col 列的第 row 行放置一个皇后 */
	public int cols[] = new int[MAX_QUEEN];
	
	public void handler(){
		//从第0列开始
		getArrangement(0);
		System.out.println(MAX_QUEEN + "皇后问题共有" + num + "种解法");
	}
	
	/**
	 * 算法核心函数
	 * @param n 当前列
	 */
	private void getArrangement(int n){
		/**
		 * 遍历该列所有不合法的行,并用rows数组记录,不合法即rows[i]=true
		 */
		boolean[] rows = new boolean[MAX_QUEEN];
		
		for(int i=0; i<n; i++){
			//不能在同一行
			rows[cols[i]] = true;
			int d = n - i;
			/**
			 * 不能在同一反斜线'\'
			 */
			if(cols[i]-d >=0)
				rows[cols[i] - d] = true;
			
			/**
			 * 不能在同一斜线'/'
			 */
			if((cols[i] + d) < MAX_QUEEN)
				rows[cols[i] + d] = true;
			
		}
		
		/**
		 * 当前皇后归位
		 */
		for(int i=0; i<MAX_QUEEN; i++){
			//判断该行是否合法
			if(rows[i])
				continue;
			
			//设置当前列合法棋子所在行
			cols[n] = i;
			
			//当前列不为最后一列时
			if(n < MAX_QUEEN-1){
				//递归
				getArrangement(n+1);
			}else{
				//累计方案个数
				num++;
				printChessBoard();
			}
		}
		
		
		
		
	}

	/**
	 * 打印棋盘信息
	 */
	private void printChessBoard() {
		// TODO Auto-generated method stub
		System.out.println("第" + num + "种走法 ");
		for(int i=0; i<MAX_QUEEN; i++){
			for(int j=0; j<MAX_QUEEN; j++){
				if(i == cols[j]){
					System.out.printf("%2s", 0);
				}else{
					System.out.printf("%2s", "*");
				}
			}
			System.out.println();
		}
	}
	
	public static void main(String[] args) {
		EightQueen eq = new EightQueen();
		eq.handler();
	}

}

【参考】


8皇后问题(java算法实现)