n皇后(回溯和剪枝)--HDU2553

问题简介:

在棋盘上放置8个皇后,使它们不同行,不同列,不同对角线。问有多少种合法的情况?
N皇后问题是8皇后问题的扩展。


一种可能的情况
过程示意图
其实n皇后问题就是对所有的皇后进行枚举,我们采用递归的写法,其中有两个技巧就是回溯和剪枝。当我们发现当前情况已经不满足时,可以将这棵搜索树直接在此处剪短,然后回溯到上一个结点,继续进行枚举。

Key1

如何递归?

每一行放置一个皇后

void dfs(int r)  // 一行一行的放置皇后,本次在第r行开始
// r是从0开始计数的
{
    if (r == n) { // 所有皇后都放置好了之后, 递归返回
        ans++;	// ans记录合法的棋局个数
        return ;
    }
    for (int i = 0; i < n; i++) {
        queen[r] = i; // 在第r行的c列放置皇后
        if (check(r, queen[r])) { // 检查是否合法
            dfs(r + 1); // 继续放下一行皇后
        }
    }
}

Key2

如何剪枝?
  • 设左上角是原点(0, 0)
  • 已经防止好的皇后的坐标是(i, j)
  • 新皇后的坐标是(r, c)

原皇后(i, j), 新皇后(r, c)
(1) 横向,不同行: i != r
(2) 纵向,不同列: j != c
(3)斜对角,从(i, j)向斜对角走a步,走到新坐标(r, c)有以下四种情况。

  • 左上角: (i - a, j - a)
  • 右上角: (i + a, j - a)
  • 左下角: (i - a, j + 1)
  • 右下角: (i + a, j + a)
bool check(int r, int c)
{
    for (int i = 0; i < r; i++) {
        if (queen[i] == c || abs(queen[i] - c) == abs(i - r))
        // 检查同列, 同一对角线是否冲突
            return false;
    }
    return true;
}

复杂度分析dfs()一行行的放置皇后,复杂度O(n!)
check()冲突检查O(n)
总的复杂度O(n x n!)

HDU–2553代码如下:

#include <bits/stdc++.h>
using namespace std;
const int maxr = 10;
int n, ans;
int queen[maxr];

bool check(int r, int c)
{
    for (int i = 0; i < r; i++) {
        if (queen[i] == c || abs(queen[i] - c) == abs(i - r))
            return false;
    }
    return true;
}


void dfs(int r)
{
    if (r == n) {
        ans++;
        return ;
    }
    for (int i = 0; i < n; i++) {
        queen[r] = i;
        if (check(r, queen[r])) {
            dfs(r + 1);
        }
    }
}



int main()
{
    int res[maxr];
    for (int i = 0; i < maxr; i++) {
        memset(queen, 0, sizeof queen);
        ans = 0;
        n = i + 1;
        dfs(0);
        res[i] = ans;
    }
    while (cin >> n) {
        if (0 == n) break;
        cout << res[n - 1] << endl;
    }
    return 0;
}

采用另一种数据结构Dancing links可以解决15皇后的规模,详细介绍见以下博客:

  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值