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;
}
}
}
}
輸出示例