n皇后问题

leetcode51. N-Queens

  • 回溯法
  • 本质:深度优先(隐式图搜索)
  • 这里不用二维数组处理起来更简单,一列一列的去看,去递归
  • 决策产生状态,巧妙利用全局标记量记录状态,来剪枝。
  • 斜线的处理方法,是直接看行列的和或差,因为斜线方程是x + y = k 和 x - y = k
  • 递归出来后面的语句记得恢复状态
  • 时间复杂度O(n^n) (暴力法下的状态空间数)
#include <iostream>
#include <vector>
#include <string>
using namespace std;

class Solution {
private:
    vector<vector<string> > ans;
    bool row[20];
    int col[20];          //col[i] 的值表示第i列的皇后在该列什么位置(位置也是从0到n)
    bool leftSlash[20];   //左斜线,像中文的捺 
    bool rightSlash[20];  //右斜线,像中文的撇
/*
斜线,方程是x + y = k 和 x - y = k 所以去查k的值,就知道这条斜线是否能放皇后,也就是下面代码呈现的
leftSlash[index + i] 和 rightSlash[index - i + n - 1]
是因为下标不能为负,所以坐标平移后是 index - i + n - 1
*/
public:
    vector<vector<string> > solveNQueens(int n) {
        dfs(0, n);
        return ans;
    }
    
    void dfs(int index, int n){  //index表示现在检查的列
        if(index >= n) {  //递归结束条件
            vector<string> rowAns;
            for(int i = 0; i < n; i++){   //存储结果,按行存储
                string tmp;
                for(int j = 0; j < n; j++){
                    if(j == col[i])
                        tmp += "Q";
                    else
                        tmp += ".";
                }
                rowAns.push_back(tmp);
            }
            ans.push_back(rowAns);
            return;
        }
        // 下面按行去 dfs, 列肯定不会冲突,因为本身涉及了按列参数去递归
        for(int i = 0; i < n; i++){
            //如果该行能放皇后,且不与斜线冲突,那么才进行里面的递归。剪枝
            if(!row[i] && !leftSlash[index + i] && !rightSlash[index - i + n - 1]){
                col[index] = i;  //让index这列的皇后在i行的位置
                row[i] = true;
                leftSlash[index + i] = true;
                rightSlash[index - i + n - 1] = true;
                dfs(index + 1, n);
                //递归出来记得用下面几句恢复状态,这样才能再进行别的 dfs 不出错
                row[i] = false;  // false 状态表示这个位置没有皇后
                leftSlash[index + i] = false;
                rightSlash[index - i + n - 1] = false;
            }
        }
    }
};

int main(){
	int n;
	cin >> n;
	vector<vector<string> > res;
	Solution *test = new Solution();
	res = test->solveNQueens(n);
	
	for(int i = 0; i < res.size(); i++){
		for(int j = 0; j < res[0].size(); j++){
			cout << res[i][j] << endl;
		}
		cout << endl;
	}
	
	cout << res[0].size() << "皇后有" << res.size() << "种摆法" << endl;
	return 0;
}

另外,骑士周游(马踏棋盘)问题,可以加上A*启发式优化方法,即改变搜索顺序。

参考 julyedu 图搜索实战班第一课

原文地址:https://www.cnblogs.com/xrszff/p/10961789.html