文章目录
问题描述
题目链接:
问题解决
初始化attack数组和queen数组
attack数组用于更新攻击范围,而queen用于更新皇后摆放位置。
设计dx、dy用于遍历八个方向的攻击范围(注意由于是扩散遍历所以应单独取值)
写出put_queen函数(实现在位置(x,y)放置皇后,同时对attack数组更新)
在写代码前需要清楚:vector容器的基本运用->vector容器创建的数组可以直接通过如:vector< int > a;vector< int > b;
a=b;直接等同将b中的数据备份到a。
//自定义函数put_queen,实现在(x,y)放置皇后,对attack数组的更新
//x、y表示放置皇后的坐标,二维数组attack表示棋盘是否可放置皇后
void put_queen(int x,int y,vector<vector<int>> &attack){
//方向数组,方便后面对8个方向进行标记
static const int dx[] ={-1,1,0,0,-1,-1,1,1};
static const int dy[] = {0,0,-1,1,-1,1,-1,1};
//通过两层循环,将皇后可能攻击到底的位置进行标记
for(int i = 1;i<attack.size();i++){//从皇后位置向1到n-1距离延伸
for(int j = 0;j<8;j++){//遍历八个方向
int nx = x+i*dx[j];//生成新位置行
int ny = y+i*dy[j];//生成新位置列
if(nx>=0&&nx<attack.size()&&ny>=0&&ny<attack.size()){
attack[nx][ny] = 1;//将新位置标记为1
}
}
}
写出回溯算法的递归函数backtrack
//k表示当前处理的行
//n表示N皇后问题
//queen存储皇后的位置
//attack标记皇后的攻击位置
//solve存储N皇后的全部解法
void backtrack(int k,int n,vector<string>&queen,vector<vector<int>>&attack,vector<vector<string>>&solve){
if(k==n){//找到一组解
solve.push_back(queen);//将结果queen存储至solve
return;//返回
}
//遍历0至n-1列,在循环中,回溯试探皇后可知放置的位置
for(int i=0;i<n;i++){
if(attack[k][i]==0){//判断当前第k行第i列是否可以放置皇后
vector<vector<int>>tmp = attack;//备份attack数组
queen[k][i]='Q';//标记该位置为'Q'
put_queen(k,i,attack);//更新attack数组
backtrack(k+1,n,queen,attack,solve);//递归试探k+1行的皇后放置
attack = tmp;//恢复attack数组
queen[k][i]='.';//恢复queen数组
}
}
}
solveNQueens函数开发
vector<vector<string>>solveNQueens(int n){
vector<vector<string>>solve;//存储最后的结果
vector<vector<int>>attack(n,vector<int>(n,0));//标记皇后的攻击位置
vector<string>queen(n,string(n,'.'));//保存皇后的位置
backtrack(0,n,queen,attack,solve);//调用backtrack求解N皇后问题
return solve;
}
测试main函数
int main(){
vector<vector<string>>result;
result = solveNQueens(8);
printf("8皇后共有%d种解法:\n\n",result.size());
for(int i = 0;i<result.size();i++){
printf("解法%d:\n",i+1);
for(int j = 0;j<result[i].size();j++){
printf("%s\n",result[i][j].c_str());
}
printf("\n");
}
return 0;
}