首页 > 其他分享 >八皇后——回溯法

八皇后——回溯法

时间:2022-10-13 16:14:01浏览次数:35  
标签:int queen attack vector 数组 回溯 皇后

八皇后问题(英文:Eight queens),是由国际象棋棋手马克斯·贝瑟尔于1848年提出的问题,是回溯算法的典型案例。 1854年在柏林的象棋杂志上不同的作者发表了40种不同的解,后来有人用图论的方法解出92种结果。如果经过±90度、±180度旋转,和对角线对称变换的摆法看成一类,共有42类。 计算机发明后,有多种计算机语言可以编程解决此问题。
问题表述为:在8×8格的国际象棋上摆放8个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。高斯认为有76种方案。   思路:每一行、一列、左斜、右斜都只能放置一个皇后,那么可以用一个数组attack表示当前可以放置的位置,(数组queen存储答案)每放置一个皇后就在她所在的行、列、左斜、右斜都进行标志,如果行、列、左斜、右斜任意一个已被标志,那么就改变皇后位置继续进行比较,直到可以放置或当前列没有位置后进行回溯   代码求解:

#include<bits/stdc++.h>
using namespace std;

//实现在(x,y)放置皇后,对attack数组的更新
//x,y表示放置皇后的坐标,二维数组attack表示棋盘是否可放置皇后
void put_queen(int x,int y,vector<vector<int>>&attack){
    //dx,dy是方向数组,方便后面对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};
    attack[x][y]=1;//将皇后位置标记为1
    //通过两层循环,将该皇后可能攻击到的位置进行标记
    for(int i=1;i<attack.size();i++){//从皇后位置向1到n-1个距离延伸
        for(int j=0;j<8;j++){//遍历8个方向
            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
            }
        }
    }
}
//回溯法求解N皇后的递归函数
//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数组
        }
    }
}

vector<vector<string>> solveNQueens(int n){
    vector<vector<string>>solve;//存储最后结果
    vector<vector<int>>attack;//标记皇后的攻击位置
    vector<string> queen;//保存皇后位置
    //使用循环初始化attack和queen数组
    for(int i=0;i<n;i++){
        attack.push_back(std::vector<int>());
        for(int j=0;j<n;j++) attack[i].push_back(0);
        queen.push_back("");
        queen[i].append(n,'.');
    }
    backtrack(0,n,queen,attack,solve);//调用backtrack求解N皇后问题
    return solve;//返回结果数组solve
}
int main(){
    vector<vector<string>>result;
    result=solveNQueens(8);
    //打印出8皇后的解法
    cout<<"8皇后共有"<<result.size()<<"种解法:"<<endl;
    for(int i=0;i<result.size();i++){
        cout<<"解法"<<i+1<<":"<<endl;
        for(int j=0;j<result[i].size();j++) cout<<result[i][j].c_str()<<endl;
        cout<<endl;
    }
    return 0;
}

 

标签:int,queen,attack,vector,数组,回溯,皇后
From: https://www.cnblogs.com/yhstsy/p/16788473.html

相关文章

  • 回溯 切割问题
    leetcode131问题描述:给你一个字符串s,请你将s分割成一些子串,使每个子串都是回文串。返回s所有可能的分割方案。回文串是正着读和反着读都一样的字符串。示例......
  • 回溯 组合问题(三)
    leetcode17题目描述:给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。答案可以按任意顺序返回。给出数字到字母的映射如下(与电话按键相同)。注意1不对......
  • 回溯 组合问题(二)
    题目描述:leetcode216找出所有相加之和为 n的 k 个数的组合,且满足下列条件:只使用数字1到9每个数字 最多使用一次 返回所有可能的有效组合的列表。该列表不能......
  • Problem P25. [算法课回溯]找出所有子集的异或总和再求和
    简单的一道回溯题,具体解法看代码,有注释#include<iostream>#include<bits/stdc++.h>#include<cstdio>#include<string>usingnamespacestd;intret=0;void......
  • 843 n皇后
    用深度优先解决n皇后问题(一条路走到黑不行再换路)#include<bits/stdc++.h>usingnamespacestd;constintN=20;charg[N][N];......
  • 回溯算法 组合问题(一)
    题目来自leetcode77题给定两个整数n和k,返回范围[1,n]中所有可能的k个数的组合。你可以按任何顺序返回答案。示例1:输入:n=4,k=2输出:[[2,4],[3,4],......
  • 递归之八皇后问题
    八皇后问题,是一个古老而著名的问题,是回溯算法的典型案例。该问题是国际西洋棋棋手马克斯·贝瑟尔于1848年提出:在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,即:任意两......
  • LeetCode回溯算法
    LetterCombinationsofaPhoneNumberLeetCode/力扣vector<string>letterCombinations(stringdigits){if(digits.length()==0)return{};map<char,str......
  • 【code基础】 回溯算法
    回溯算法也叫回溯搜索法,其本质是穷举,也可以加上剪枝操作进行优化回溯是递归的副产品,只要有递归就存在回溯的思想回溯算法可以抽象为树形结构回溯法解决如下问题:组合......
  • 我们一起搞回溯(1)
     其实回溯算法中很关键的一个问题是递归。我们都知道递归,也看得懂递归,但有的时候在实际操作过程中却不知道怎么使用,有时候还会被搞晕。那我们就先来搞清楚递归。首先我们......