暴力会超时
暴力算法:
#include <stdio.h>
#include <string.h>
#define MAX 14
int N, ans; // N是棋盘的大小,ans是解决方案的总数
char board[MAX][MAX]; // 存储棋盘布局,'*'表示可放置皇后,'.'表示不可放置
int use[MAX]; // 标记列是否已放置皇后
int diag1[MAX * 2 - 1]; // 标记对角线(从左上到右下)是否已放置皇后
int diag2[MAX * 2 - 1]; // 标记对角线(从右上到左下)是否已放置皇后
// 深度优先搜索函数,y表示当前行
void DFS(int y) {
if (y > N) { // 如果已经放置了N行皇后,找到一个解决方案
ans++;
return;
}
for (int x = 1; x <= N; x++) {
// 如果当前位置不可放置或者当前行的该列或对角线上已有皇后,则跳过
if (board[y][x] == '.' || use[x] || diag1[y + x] || diag2[N - x + y]) {
continue;
}
// 标记当前位置的列和对角线为已放置
use[x] = diag1[y + x] = diag2[N - x + y] = 1;
// 递归放置下一行的皇后
DFS(y + 1);
// 回溯,清除标记
use[x] = diag1[y + x] = diag2[N - x + y] = 0;
}
}
int main() {
scanf("%d", &N); // 读取棋盘大小
for (int i = 1; i <= N; i++) {
scanf("%s", board[i] + 1); // 读取棋盘布局,+1是因为数组是从1开始的
}
memset(use, 0, sizeof(use)); // 初始化列标记数组
memset(diag1, 0, sizeof(diag1)); // 初始化对角线1标记数组
memset(diag2, 0, sizeof(diag2)); // 初始化对角线2标记数组
ans = 0; // 初始化解决方案计数器
DFS(1); // 从第一行开始递归搜索
printf("%d\n", ans); // 输出解决方案总数
return 0;
}
可以使用深度优先搜索(DFS)结合位运算的方法来解决该问题。
通过位运算表示皇后的放置状态和攻击范围,对每一行的每一个可能位置进行搜索,最终找出满足条件的皇后放置方案的数量。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// 定义全局变量
int n, sp[15], full, ans;
// 计算一个数的最低位的 1
int lowbit(int x) {
return x & (-x);
}
// 深度优先搜索函数,用于解决 N 皇后问题
void dfs(int lie, int leftmove, int rightmove, int line) {
// 如果列都填满了,说明找到一种放置皇后的方案
if (lie == full) {
ans++;
return;
}
// 计算可以放置皇后的位置
int pos = (~(lie | leftmove | rightmove | sp[line])) & full;
while (pos) {
int Low = lowbit(pos);
pos -= Low;
// 递归调用 dfs,更新列、左斜线、右斜线和行
dfs(lie + Low, (leftmove + Low) << 1, (rightmove + Low) >> 1, line + 1);
}
}
int main() {
scanf("%d", &n);
full = (1 << n) - 1;
ans = 0;
// 初始化 sp 数组,用于标记不可放置皇后的位置
for (int i = 1; i <= n; i++) {
char s[16];
scanf("%s", s);
for (int j = 1; j <= n; j++) {
if (s[j - 1] == '.') {
sp[i] |= (1 << (n - j));
}
}
}
// 开始深度优先搜索
dfs(0, 0, 0, 1);
printf("%d\n", ans);
return 0;
}