NQueens 与 递归,回溯

来源:互联网 发布:系统性能优化 编辑:程序博客网 时间:2024/05/16 17:19

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); 是局部变量采用连续传递计数的,还可以采用全局变量。

0 0
原创粉丝点击