NQueens 与 递归,回溯
2015-11-09 18:45
337 查看
NQueens 问题描述:
规则:两个皇后 在同一行,同一列,同一斜线上都会打架 (即皇后不能放在同一行,同一列,同一斜线上) 上图是 8*8 棋盘放置8个皇后的一种方法示意图。 现有 n*n 棋盘,放 n 个皇后,提供算法,求一共有多少种不同的放置皇后的方法。
思路:(回阙法)
1)第一步有 n*n 个位置可以下,后面每一步,需要遍历棋盘,根据规则检验,确定位置。因此需要遍历棋盘。
2)每下一步前,都需要根据规则检验。这里可以用集合记录已放置皇后的位置(col,row),所在斜线(row+col, row-col)信息。
3)如果遍历完一次不满足条件,则需要将当前皇后信息都移出集合,进行下一次遍历试探。即回溯思想。
4)如果能顺利遍历完最后一行,最后一列,则解法count++;
下面是C#代码示例:
public class Solution { ICollection<int> colSet = new HashSet<int>(); //column ICollection<int> diaSet1 = new HashSet<int>(); //diagonal ICollection<int> diaSet2 = new HashSet<int>(); public int TotalNQueens(int n) { int count = TotalQueensHelper(0,0,n); return count; } private int TotalQueensHelper(int row, int count, int n){ for(int col =0; col<n; col++){ if(colSet.Contains(col)) continue; int dia1 = row + col; if(diaSet1.Contains(dia1)) continue; int dia2 = row - col; if(diaSet2.Contains(dia2)) continue; if(row == n-1){ //顺利遍历完 count ++; }else{ colSet.Add(col); diaSet1.Add(dia1); diaSet2.Add(dia2); count = TotalQueensHelper(row+1,count,n); // colSet.Remove(col); diaSet1.Remove(dia1); diaSet2.Remove(dia2); } } return count; } }
一些关键点:
1) 二维数组中,同一斜线的数特性:row+col('/'该趋势斜线),row-col('\'该趋势斜线) 为同一个数 2) 函数调用,系统的处理工作: 当一个函数的运行期间调用另一个函数的时候,在运行被调用函数之前,系统都会先完成三件事: (1)将所有的实在参数、返回地址等信息传递给被调用的函数保存; (2)为被调用的局部变量分配存储区; (3)将控制转移到被调用的函数的入口。 而从被调用函数返回调用函数之前,系统也应完成三件事: (1)保存被调用函数的计算结果; (2)释放被调用函数的数据区; (3)依照被调用函数保存的返回地址将控制转移到调用函数上。 当有多个函数构成嵌套语句时,按照,“后调用先返回”的原则,上述的函数之间的信息传递和控制的转移必须通过“栈”来实现,即系统将整个程序运行时间所需的数据安排在一个栈中,每当调用一个函数时,就为它在栈顶分配一个存储区,每当一个函数退出时,就释放它的存储空间,则当前正在运行的函数的数据区必在栈顶。 3) 递归是函数调用的一种特殊调用。
private int TotalQueensHelper(int row, int count, int n){ for(int col =0; col<n; col++){ if(colSet.Contains(col)) continue; int dia1 = row + col; if(diaSet1.Contains(dia1)) continue; int dia2 = row - col; if(diaSet2.Contains(dia2)) continue; if(row == n-1){ //顺利遍历完 count ++; }else{ colSet.Add(col); diaSet1.Add(dia1); diaSet2.Add(dia2); count = TotalQueensHelper(row+1,count,n); // colSet.Remove(col); diaSet1.Remove(dia1); diaSet2.Remove(dia2); } } return count; }
这里需要注意的是:
被调用函数,运行return后,是返回到调用函数继续执行。这里跟循环里的 return 退出循环不一样。
递归里的 return 是返回到上一层调用。
这里的 count = TotalQueensHelper(row+1,count,n); 是局部变量采用连续传递计数的,还可以采用全局变量。
相关文章推荐
- 动易2006序列号破解算法公布
- Ruby实现的矩阵连乘算法
- C#插入法排序算法实例分析
- 有关数据库SQL递归查询在不同数据库中的实现方法
- 超大数据量存储常用数据库分表分库算法总结
- C#数据结构与算法揭秘二
- C#中的递归APS和CPS模式详解
- C#冒泡法排序算法实例分析
- WinForm实现按名称递归查找控件的方法
- 算法练习之从String.indexOf的模拟实现开始
- C#算法之关于大牛生小牛的问题
- 使用SqlServer CTE递归查询处理树、图和层次结构
- C#实现的算24点游戏算法实例分析
- C#中的尾递归与Continuation详解
- c语言实现的带通配符匹配算法
- 浅析STL中的常用算法
- 算法之排列算法与组合算法详解
- C++实现一维向量旋转算法
- Ruby实现的合并排序算法
- C#折半插入排序算法实现方法