1.题目描述
在N*N的方格棋盘放置了N个皇后,使得它们不相互攻击(即任意2个皇后不允许处在同一排,同一列,也不允许处在与棋盘边框成45角的斜线上。
你的任务是,对于给定的N,求出有多少种合法的放置方法。
在N*N的方格棋盘放置了N个皇后,使得它们不相互攻击(即任意2个皇后不允许处在同一排,同一列,
也不允许处在与棋盘边框成45角的斜线上。你的任务是,对于给定的N,求出有多少种合法的放置方法。
在N*N的方格棋盘放置了N个皇后,使得它们不相互攻击(即任意2个皇后不允许处在同一排,同一列,也不允许处在与棋盘边框成45角的斜线上。
你的任务是,对于给定的N,求出有多少种合法的放置方法。
2.思路
这道题目,首先确定搜什么。因为每一行仅且必须放一个皇后,所以我们可以按照顺序一行一行放置皇后,那么就搜每一行得皇后放在哪个位置。
接下来是状态表示,我们判断一个位置是否可以防止皇后,要考虑它的上方,左上 45°,右上 45° 是否放置了皇后,这些就是我们需要在深搜过程中维护的当前状态。
3.方案
a.二维数组
#include <iostream>
using namespace std;
int a[11][11];
int n, res;
bool check (int x, int y) {
// 检查同一列
for (int i = 0; i < n; i++)
if (a[i][y] == 1) return false;
//检查左上角45°
for (int i = x - 1, j = y - 1;
i >= 0 && j >= 0; i--, j--)
if (a[i][j] == 1) return false;
//检查右上角45°
for (int i = x - 1, j = y + 1;
i >= 0 && j < n; i--, j++)
if (a[i][j] == 1) return false;
return true;
}
void solve (int cur) {
if (cur == n) { // 已经填好最后一行
res++;
return;
}
for (int i = 0; i < n; i++) {
if (!check(cur, i)) continue;
a[cur][i] = 1;
solve (cur + 1);
a[cur][i] = 0; // 撤销状态(改回来)
}
}
int main() {
cin >> n;
solve(0);
cout << res << endl;
return 0;
}
b.一维数组
#include <iostream>
using namespace std;
int a[11];
int n, res;
void solve(int cur) {
if (cur == n) {
res++;
return;
}
for (int i = 0; i < n; i++) {
bool isT = true;
for (int row = 0; row < cur; row++) {
if (a[row] == i || row + a[row] == i + cur
|| a[row] - row == i - cur) {
isT = false;
break;
}
}
if (isT) {
a[cur] = i;
solve (cur + 1);
//a[cur] = 0;
}
}
}
int main() {
cin >> n;
solve(0);
cout << res << endl;
return 0;
}
c.位运算
#include <cstdio>
using namespace std;
int dfs(int cur, int n, int lb, int rb, int cb){
if (cur > n) return 1;
int ban = lb | rb | cb, ret = 0;
for (int i = 0; i < n; i++){
if ((ban >> i) & 1) continue;
ret += dfs(cur + 1, n, (lb | (1 << i)) << 1, (rb | (1 << i)) >> 1, cb | (1 << i));
}
return ret;
}
int main(){
int n, ans[15];
for (int i = 1; i <= 10; i++) ans[i] = dfs(1, i, 0, 0, 0);
while(scanf("%d", &n) != EOF && n > 0)
printf("%d\n", ans[n]);
return 0;
}