N皇后问题
把n个皇后放在n×n的国际象棋棋盘的格子上,要求任意两个皇后不能处于同一条水平线、垂直线或对角线。给出任意一个可行解。
算法:
设横纵座标的范围都是离散闭区间[0,n – 1]。
先确定每个皇后的横座标。这里通过随机方法确定,将离散闭区间[0,n – 1]的整数打乱顺序并放入一个数组。按顺序访问这个数组,尝试放置每个皇后于指定的横座标。
尝试放置第i个皇后时,纵座标也用同样的方法随机确定。尝试放置后,先进行检查,考察是否有任意两个皇后的摆放位置不符合要求。如果都符合,则尝试摆放第(i + 1)个皇后;如果不符合,则该皇后的纵座标要更改;如果这个皇后在这一列无论摆放哪个位置都不符合要求,就证明之前的摆放方案不对,更改第(i – 1)个皇后的纵座标。
如果n个皇后都能摆放完毕,算法结束。
仅当n = 1或n≥4时才有解。
代码实现:
#include <algorithm>
#include <bitset>
#include <chrono>
#include <iostream>
#include <random>
using namespace std;
const int nmax = 1024;
struct point { int x, y; };
uniform_int_distribution<int> u(0, INT32_MAX); mt19937_64 r;
int n, x[nmax]; point c[nmax]; bitset<nmax> b[nmax];
inline bool check(int n, const int* y) {
for (int i = 0; i < n - 1; ++i) {
if (c[i].x == c[n - 1].x || c[i].y == c[n - 1].y || abs(c[i].x - c[n - 1].x) == abs(c[i].y - c[n - 1].y)) return false;
}
return true;
}
bool solve(int i) {
if (i == n) return true;
int* y = new int[n];
copy(x, x + n, y); shuffle(y, y + n, r);
for (int j = 0; j < n; ++j) {
c[i] = { x[i], y[j] };
if (check(i + 1, y)) {
if (solve(i + 1)) { delete[] y; return true; }
}
}
delete[] y; return false;
}
int main() {
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
r.seed(chrono::steady_clock::now().time_since_epoch().count());
for (;;) {
cout << "Enter the size of the chessboard, or a single 0 to exit: ";
cin >> n;
switch (n) {
case 0: return 0;
case 1: cout << "X" << endl; break;
case 2: case 3: cout << "No solution." << endl; break;
default:
for (int i = 0; i < n; ++i) { b[i].reset(); x[i] = i; }
shuffle(x, x + n, r);
solve(0);
for (int i = 0; i < n; ++i) b[c[i].x][c[i].y] = true;
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j)
if (b[i][j]) cout << 'X';
else cout << '.';
cout << endl;
}
}
}
}
输出示例