Hdu2553 - N皇后问题 - 经典暴力回溯问题(位运算做法)

N皇后问题

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)

Problem Description
 
在N*N的方格棋盘放置了N个皇后,使得它们不相互攻击(即任意2个皇后不允许处在同一排,同一列,也不允许处在与棋盘边框成45角的斜线上。
你的任务是,对于给定的N,求出有多少种合法的放置方法。

 
Input
共有若干行,每行一个正整数N≤10,表示棋盘和皇后的数量;如果N=0,表示结束。
 
Output
共有若干行,每行一个正整数,表示对应输入行的皇后的不同放置数量。
 
Sample Input
1
8
5
0

Sample Output

1
92
10

Author

cgf
 
Source
 

思路

我们知道n皇后问题可以通过三个数组标记来判断合法位置 - Hdu2553 - N皇后问题 - 经典暴力回溯问题(非位运算做法)

当然,其实我们可以用位运算来表示各个状态,相比于数组既节省一些空间,常数也要小一些,也就是略快一些

我们可以使用l表示上一行影响向左下延伸的状态,c表示上一行影响向下延伸的状态,r表示上一行影响向右下延伸的状态,那么l,c,r或运算之后,1表示该位置会被攻击,0表示可以放皇后

如果放皇后的状态用b表示,那么放完皇后之后影响要加入新皇后的影响,l - > l | b, c -> c | b, r -> r | b

向下一行攻击时 l攻击的位置相对于当前行要左移,r攻击的位置相对当前行要右移,即l  << 1, r >> 1。

具体看代码注释

代码

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 12;
int n, ans;
int mp[N];
void dfs(int cur, int l, int c, int r){
    if (cur == n + 1){
        ans ++;
        return ;
    }
    int a = l | c | r;//用于表示各个位置是否合法,a的某一位为1表示不能放,也就是会被前面的皇后攻击到
    for (int i = 0; i < n; ++ i){
        int b = 1 << i;//表示放在倒数第i + 1位的状态
        if (~ a & b){//a取反后1表示能放,和b与运算之后,如果b状态合法,那么一定不为0,否则为0
            dfs(cur + 1, (l | b) << 1, c | b, (r | b) >> 1);
            //或运算后l,c,r的倒数第i + 1位会变成1(加入该行皇后的位置),由于对角线,l传到下一层的值应左移一位,r右移一位
        }
    }
}
int main()
{

    while (cin >> n && n){
        if (mp[n]){
            cout << mp[n] << endl;
            continue;
        }
        ans = 0;
        dfs(1, 0, 0, 0);
        mp[n] = ans;//记录算过的值,不然会超时
        cout << ans << endl;
    }
    return 0;
}
发布了21 篇原创文章 · 获赞 0 · 访问量 810

猜你喜欢

转载自blog.csdn.net/tourist1412/article/details/105188198