N皇后问题
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Problem Description
在N*N的方格棋盘放置了N个皇后,使得它们不相互攻击(即任意2个皇后不允许处在同一排,同一列,也不允许处在与棋盘边框成45角的斜线上。
你的任务是,对于给定的N,求出有多少种合法的放置方法。
你的任务是,对于给定的N,求出有多少种合法的放置方法。
Input
共有若干行,每行一个正整数N≤10,表示棋盘和皇后的数量;如果N=0,表示结束。
Output
共有若干行,每行一个正整数,表示对应输入行的皇后的不同放置数量。
Sample Input
1
8
5
0
Sample Output
1
92
10
Author
cgf
Source
思路
总体思路肯定是递归遍历解空间树,计算所有合法放置方式,复杂度是O(N!)(10的阶乘是3628800)
对于本题每次重复算会超时,所以我们要记录算过的答案,不然会TLE
根据题意我们知道一行只能放一个皇后,那么本题的重点是在每层判断皇后位置的合法性
1.对于每列,我们只需要用一个col数组标记,因为同理一列不可能存在两个皇后
2. 对于左上到右下的斜对角线,我们可以数字1 ~ 2 * n - 1标记每条对角线
6 | 7 | 8 | 9 | 10 | 11 |
5 | 6 | 7 | 8 | 9 | 10 |
4 | 5 | 6 | 7 | 8 | 9 |
3 | 4 | 5 | 6 | 7 | 8 |
2 | 3 | 4 | 5 | 6 | 7 |
1 | 2 | 3 | 4 | 5 | 6 |
对于第cur层的第i个位置如果lr[i - cur + n]为1,那么表示这条对角线已被标记了
3.对于右上到左下的斜对角线也同理
11 | 10 | 9 | 8 | 7 | 6 |
10 | 9 | 8 | 7 | 6 | 5 |
9 | 8 | 7 | 6 | 5 | 4 |
8 | 7 | 6 | 5 | 4 | 3 |
7 | 6 | 5 | 4 | 3 | 2 |
6 | 5 | 4 | 3 | 2 | 1 |
对于第cur层的第i个位置如果rl[i + cur]为1,那么表示这条对角线已被标记了
代码
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 12;
int lr[N << 1], col[N], rl[N << 1];
int n, ans;
int mp[N];
void dfs(int cur){
if (cur == n + 1){
ans ++;
return ;
}
for (int i = 1; i <= n; ++ i){
if (col[i] || lr[i - cur + n] || rl[cur + i])continue;
col[i] = lr[i - cur + n] = rl[cur + i] = 1;
dfs(cur + 1);
col[i] = lr[i - cur + n] = rl[cur + i] = 0;
}
}
int main()
{
while (cin >> n && n){
if (mp[n]){
cout << mp[n] << endl;
continue;
}
memset(lr, 0, sizeof(lr));
memset(rl, 0, sizeof(rl));
memset(col, 0, sizeof(col));
ans = 0;
dfs(1);
mp[n] = ans;
cout << ans << endl;
}
return 0;
}