C++ dfs状态的表示(五十三)【第十三篇】

今天我们将来求解N皇后问题。

1.N皇后问题

N 皇后问题是一个经典的问题,在一个 N×N 的棋盘上放置 N 个皇后,每行刚好放置一个并使其不能互相攻击(同一行、同一列、同一斜线上的皇后都会自动攻击)。

图片

上图就是一个合法的 8 皇后的解。
N 皇后问题是指:计算一共有多少种合法的方法放置 N 个皇后。

很显然,我们依然会用 dfs 来求解 
N 皇后问题,我们的搜索策略如下。

从第 0 列开始,我们依次给每一列放置一个皇后,对于一个确定的列,我们只需要去枚举放置的行即可,在保证放置合法的情况下,一直搜索下去。

下图是 N=4 时搜索树的局部形态:

图片

上图中每个状态下的 
−2,−1,0 表示的是该状态的冲突次数(在多少列或斜线发生冲突),只有当冲突次数为 
0 时才是合法状态。

确定了搜索策略,现在我们还有一个问题没有解决,那么就是如何判断是否发生了冲突。因为我们是逐列放置的,所以列内是不会冲突的,对于行也很好处理,如果某行被占用了,只需要用一个数组标记即可。

而最难处理的是同一斜线了。一种方法是我们可以直接暴力枚举这个皇后对应的两条对角线上的点,判断是否有冲突。但是这种方法,既麻烦,效率也比较低。下面我们介绍一种巧妙的方法。

图片

有一个规律,这条对角线上的位置的行加列的值相同,都是 4。

0+4=1+3=2+2=3+1=4+0=4

并且每条对角线上行加列的值互不相同,所以我们就可以根据行加列的值判断是哪一条对角线。

图片

而这样的对角线上的位置的坐标的行减去列的值也是相同的,都是 −2。

而我们发现,对于每条对角线,和值或者差值都是不一样的,而我们正好可以用这一点来标记一条对角线是否被占用,使得标记对角线就像标记列一样简单了。

但是可能存在负数,为了使负数变成整数,我们让差值再加上 
N,即:行 − 列 + N。

代码:

#include <iostream>
using namespace std;
int ans = 0;
bool row[10], x1[20], x2[20];
bool check (int i, int c) {
    return !row[i] && !x1[i+ c] && !x2[i - c + 8];//合法性
}
void dfs(int c) {//枚举第C列的摆放
    if (c == 8) {
        ans++;
        return ;
    }
    for (int i = 0; i < 8; i++) {//枚举第i列
        if (check(i, c)) {//无冲突就可以摆放
            row[i] = x1[i + c] = x2[i - c + 8] = true;
            dfs(c + 1);
            row[i] = x1[i + c] = x2[i - c + 8] = false;
        }
    }
}
int main() {
    dfs(0);
    cout << ans << endl;
    return 0;    
}
  • 9
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值