八皇后问题(用数字压缩状态,使劲节省内存)

1.问题描述:


在8×8格的国际象棋上摆放8个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法

2.分析:

2.1 用数字表示摆放位置思路:

首先,每一行每一列都会有一个皇后,并且左右每个斜线都不能超过一个皇后,如果将皇后位置排列画到图上

 皇后的摆放方式有2 的64次方中,如果将这些摆放方式作为数字,用数字的在第几位表示皇后在哪一行,每一位上的数字序号表示皇后在哪一列,即:

1758

1(1行1列)7(2行7列)5(3行5列)8(4行8列)

每一位只有8个数字选择,那么总共的摆放数量有 8的8次方,还是很大

其实不用每一个数字都拿来校验,可以在数字从第一位开始放置数字,第二位放置数字的时候校验是否与之前的皇后攻击,校验方法,将当前数字(列)在第几位(行)与之前的每一个数字对应的行列进行判断是否攻击,如果攻击则结束,否则将当前放置的数字加入到数字序列中,如果到达第八位(第八行)表示八个皇后都已放置完成,数量加一

判断攻击方式:

取出两个位置的行列(x1,y1),(x2,y2) 判断条件:

x1 != x2

y1 != y2

(x1-x2) != |(y1-y2)|  //斜线向左或向右

代码如下:

#include <bits/stdc++.h>

typedef unsigned long long ULL;
using namespace std;

bool valid_queen(int num, int x, int idx) {
    // 将数字转化为对应的坐标进行校验,判断是否存在列,行,斜线攻击
    int col;
    int tmp_num = num;
    for (int i = 0; i < idx; i++) { // 遍历之前已经放置好的每一个皇后
        if (tmp_num == 0) {
            break;
        }
        int row = i + 1; // 之前已经放置的皇后的行
        col = (tmp_num % 10); // 之前放置皇后的列
        tmp_num /= 10;
        if (col == x) {
            return false;
        }
        if ((idx - row) == (x - col)) {
            return false;
        }
        if ((idx - row) == -(x - col)) {
            return false;
        }
    }
    return true;
}

// 输入数字,填写的位数
int dfs(int num, int x, int idx) {
    // 如果可以添加,则添加,同时判断如果位数满8则 返回1,位数未满8位dfs当前状态
    bool valid = valid_queen(num, x, idx);
    if (valid) {
        num += x * (int) pow(10, idx - 1);
        if (idx == 8) {
            cout << num << endl;
            return 1;
        }
        //在下一行添加皇后
        int ans = 0;
        for (int i = 1; i <= 8; i++) {
            ans += dfs(num, i, idx + 1);
        }
        return ans;
    } else {
    // 如果无法继续添加,返回0
        return 0;
    }

}


int main() {
    int s = dfs(0, 0, 0);
    cout << "ans:" << s << endl;
    return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值