皇后问题 java求解,【leetcode】51. N-Queens 求解N皇后问题的所有解

1. 题目

The n-queens puzzle is the problem of placing n queens on an n×n chessboard such that no two queens attack each other.

1ae06f63c90dc462e3a058b9b95591a2.png

Given an integer n, return all distinct solutions to the n-queens puzzle.

Each solution contains a distinct board configuration of the n-queens' placement, where 'Q' and '.' both indicate a queen and an empty space respectively.

For example,

There exist two distinct solutions to the 4-queens puzzle:

[

[".Q..", // Solution 1

"...Q",

"Q...",

"..Q."],

["..Q.", // Solution 2

"Q...",

"...Q",

".Q.."]

]

2. 思路

回溯的方式求解。第一步将左上顶点置位作为起始点。第一个点一定是有效位。然后每次试探的为下一行找到合适的位置,如果找到了递归的继续找下一行,如果下一行超过了N,则说明得到一个有效解。如果下一行找不到合适的位置,或者是已经找到了有效解,则改为从当前最后一行的当前有效位置的下一个位置开始往后试探,扎到一个新的有效位置。如果在当前行找不到,则回退这一行,从上一行的位置开始往后找。如果一直回退到全部-1行,则全部递归完成。

试探某一个位置是否有效,通过已有的皇后影响的位置来判断。如果[i, j]位置有皇后,从二维坐标平面上考虑,影响的空间实际上是x=i; y=j; x+y=i+j; x-y=i-j四条线段覆盖的所有的点。可以通过四个数组来标记。

3. 代码

耗时:113ms

// 棋盘的横坐标是x,纵坐标是y。

// 横、纵、左斜、右斜四个方向可以用四个一次函数表示

// 对于坐标[i,j ]对应的四条线分别是:

// 横线可以用x=i [0,n-1]

// 纵线是y=j [0,n-1]

// 反斜线是x-y=i-j [-n+1,n-1]

// 正斜线是x+y=i+j [0,2n-2]

// 因此用四个数组可以表示这棋盘上所有被杀点, 在实现时为了方便可以用一个长度为6n-2的数组来存储

class ChessBoard {

public:

bool* kill; // x,y,x-y,x+y分别对应区段为[0,n)[n,2n)[2n,4n-1)[4n,6n-1)

int n;

ChessBoard(int N) : kill(NULL), n(N) {

kill = new bool[6*N];

for (int i = 0; i < 6*N; i++) {

kill[i] = false;

}

}

~ChessBoard() {

delete[] kill;

}

vector four_lines(int i, int j) {

vector l;

l.push_back(i);

l.push_back(n + j);

l.push_back(2 * n + i -j + n -1);

l.push_back(4 * n + i + j);

return l;

}

void add(int i, int j) {

vector pos = four_lines(i, j);

for (int k = 0; k < 4; k++) {

kill[pos[k]] = true;

}

}

void del(int i, int j) {

vector pos = four_lines(i, j);

for (int k = 0; k < 4; k++) {

kill[pos[k]] = false;

}

}

bool valid(int i, int j) {

vector pos = four_lines(i, j);

for (int k = 0; k < 4; k++) {

if (kill[pos[k]]) {

return false;

}

}

return true;

}

};

class Solution {

public:

vector> solveNQueens(int n) {

vector> ret;

ChessBoard cb(n);

vector ans; // 第i个元素存储第i+1行的列号

ans.push_back(0);

cb.add(0, 0);

//cout << "start i=0 j=0" << endl;

while (!ans.empty()) {

if (tryNQueens(cb, ans)) { // 在一个有效的部分布局下填充下一个行

if (ans.size() == cb.n) {

fill(ret, ans);

move_next(cb, ans);

}

} else {

move_next(cb, ans);

}

}

return ret;

}

void move_next(ChessBoard& cb, vector& ans) {

if (ans.size() == 0) { return ;}

while (ans.size() != 0) {

int i = ans.size() - 1;

int j = ans.back();

ans.pop_back();

cb.del(i, j);

j++;

for (; j < cb.n; j++) {

if (cb.valid(i, j)) {

ans.push_back(j);

cb.add(i, j);

//cout << "move next pos: i=" << i << " j=" << j << endl;

return ;

}

}

//cout << "rool back row=" << ans.size() << endl;

}

return ;

}

bool tryNQueens(ChessBoard& cb, vector& ans) {

if (ans.size() == cb.n) {

return true;

}

int i = ans.size();

for (int j = 0; j < cb.n; j++) {

if (cb.valid(i, j)) {

ans.push_back(j);

cb.add(i, j);

//cout << "try next row: i=" << i << " j=" << j << endl;

return true;;

}

}

//cout << "try fail, i=" << i << endl;

return false;

}

void fill(vector>& ret, vector& ans) {

//cout << "[Find]" << endl;

string temp;

for (int i = 0; i < ans.size(); i++) {

temp += ".";

}

vector str_ans;

for (int i = 0; i < ans.size(); i++) {

string s = temp;

s[ans[i]] = 'Q';

str_ans.push_back(s);

//cout << s << endl;

}

ret.push_back(str_ans);

return ;

}

};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值