算法——回溯法(八皇后问题)

 

 

 

 

回溯法是比枚举法更加高效的一种算法思想,直接枚举法的优点是思路和程序都很简单,缺点在于无法简便地减小枚举量——必须生成所有可能的解,然后一一检查。在递归构造中,生成和检查过程可以有机的结合起来,从而减少不必要的枚举。当把问题分成若干步骤并递归求解时,如果当前步骤没有合法选择,则函数将返回上一级递归调用,这种现象称为回溯。八皇后问题是回溯法的最直接应用。

 

【问题描述】:在国际象棋中,皇后作为最有威力的棋子,横、竖、斜都可以走,步数不受限制。在棋盘上放置8个皇后,使得它们互不攻击,此时每个皇后的攻击范围为同行同列同对角线,要求找出所有的解。

 

【分析】:比较简单的思路是把问题转化为“从64个格子中选8个格子”,这是组合生成问题,最终的结果会很大,这并不是一个很好的模型。经过思考,不难发现以下事实:恰好每行每列各放置一个皇后。如果C[x]表示第x行皇后的列编号,则问题变成了全排列生成问题。而0~7的排列一共只有8!=40320个,枚举量不会超过它。

【程序】:

 
void show() 
{
     for(int i=0;i

 

 

 

 

所谓回溯法,一定要有递归的终止条件。八皇后问题每次递归的终止条件为行数等于8。如果递归的行数达到8,则解法自加1,并将解法中各皇后的坐标进行打印。先定义全局变量max=8,sum为解法的数量,s[8]表示皇后的位置。x表示行数,上述代码将皇后逐行放置,因此皇后肯定不会横向攻击,故只需检查是否纵向和斜向攻击即可。然后对每行的八个位置的合法性进行检查,条件”s[x]==s[i]“用来判断皇后是否在同一列,条件“x-s[x]==i-s[i] || x+s[x]==i+s[i]”用来判断皇后是否在同一对角线上。其原理如下图所示:

 

 

算法——回溯法(八皇后问题)_第1张图片

 

 

 

 

【优化】:该程序可以对判断皇后合法性的条件进行进一步简化,程序效率可以继续提高。利用二维数组vis[2][]直接判断当前位置所在的列和两个对角线是否已有其它皇后。

void eightQueens(int x)
{
	if(x==max){
		sum++;
		show();
	}
	else for(int j=0;j

定义全局变量vis[3][15],vis[0]表示列,vis[1]表示副对角线,vis[2]表示主对角线。相应的,根据上面的图可知,vis[0][8]中,8代表共有8列,vis[1][15]中,15代表副对角线共有15条,同理,vis[2][15]中,15也代表主对角线共有15条。用j+x表示副对角线,取值为0~14;用j-x表示主对角线,取值为-7~7,同时加上7,即max-1,取值变为0~14。若三个变量同时为0,则该位置合法,放置皇后之后,将该位置所代表的列、主对角线、副对角线全部设为1。当递归完毕,返回上一层后,再将该位置设为0,在这一行上寻找下一个合法位置。利用二维数组,有效地避免了每次判断皇后位置合法性时的遍历时间,提高了程序的效率。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(算法——回溯法(八皇后问题))