用C++编写的代码块如下所示:
class Solution {
public:
//定义一个结果二维动态数组reslult用来保存数组
vector<vector<string>> result;
vector<vector<string>> solveNQueens(int n) {
//定义路径动态数组path包含n个字符串元素,每个字符串元素由n个.构成完成路径数组path的初始化
vector<string> path(n,string(n,'.'));
int row=0;//定义行变量用来控制遍历第几行初始设为0
backTracking(n,row,path);//回溯函数
return result;
}
void backTracking(int n,int row,vector<string> path){
if(row==n){//当控制的行遍历了第n-1行后并加一即表示到达了叶子结点且成功了将对应的叶子路径的解加入二维结果动态数组result中
result.push_back(path);
return;
}
//表示遍历row行的每个列col用来判断是否能够暂时满足条件而加入路径动态数组path中去
for(int col=0;col<n;col++){
if(isVilad(n,row,col,path)){//如果当前的行与列能够满足皇后存放的条件(同行,同列,同对角线(45度与135度)均没有其它皇后但是此时同行不需要比较因为只要该行确定了列下面递归调用回溯函数就是从row+1行开始遍历)
path[row][col]='Q';//令row个字符串的col列的字符变为Q
backTracking(n,row+1,path);
path[row][col]='.';//令之前存放皇后Q的位置重新存放'.'字符
}
}
}
bool isVilad(int n,int row,int col,vector<string> path){
//判断同列是否满足要求
for(int i=0;i<row;i++){
if(path[i][col]=='Q'){//表示同列之前的列存在其它皇后
return false;
}
}
//判断45度(即左上位置)位置是否不满足要求(存在其它皇后)
for(int i=row-1,j=col-1;i>=0&&j>=0;i--,j--){
if(path[i][j]=='Q'){
return false;
}
}
//判断上方的135度位置(即右上位置)是否有其它皇后
for(int i=row-1,j=col+1;i>=0&&j<n;i--,j++){
if(path[i][j]=='Q'){
return false;
}
}
//表示上方的(下方的根本还没有设置皇后因此不需要考虑)同行同列以及同对角线都没有其它皇后直接输出true表示该位置可以防止皇后
return true;
}
};
具体解释如下:
首先对于一般回溯算法的框架结构为:
def backtrack(路径,选择列表){
if(满足结束条件)
result.add(路径);
return;
for 选择 in 选择路径//一般是要将从头到尾的所有可能都加入到该for循环中去
if 选择 in 路径://表示该选择已经选中并加入路径中了
continue;
路径.add(选择);
backtrack(新路径,选择列表);
路径.remove(选择);
}
基于该框架构型此N皇后问题的解题思路为:
首先定义一个空的二维动态数组result用来存在最终的所有结果,对于其中的路径动态数组为path将其初始化为n个字符串元素其每个字符串都是有n个.构成,定义行变量n为0调用backtrack(n,row,path)方法,该方法为先判断行变量row是否等于n即达到了叶子结点,满足条件就将路径数组path作为元素加入到结果二维动态数组result中去并结束本次函数return;,如果不满足就在当前的row下遍历所有的col来找出和之前已设定的皇后位置不矛盾的col(具体判断方法为isVilad(n,row,col,path)具体可以看代码中的注释十分详细)在该列满足条件后,就调用backTracking(n,row+1,path);来判断第row+1行的皇后位置的确定,实际上就是以row行确定的位置为根节点来寻找其子树中满足条件的路径并随机加入其中,当该row+1结束后row行确定的位置的所有子树已经遍历完毕,因此将该位置重新变为.,并由for循环接着找该行是否有其它的col可以满足条件,满足则加入其中.代码执行完毕之后就会自动将所有的满足条件的路径都加入其中。
代码.
主要目的是要基于该经典的回溯算法,来理解其它的各种类型的回溯算法的思想与代码块的书写。