N皇后问题的递归和非递归(栈的方式)解决

题目: 输入N,有N个皇后使得它们互不攻击,即任意两个皇后都不能处在同一行、同一列或同一对角线上。

Tips :  对于windows端 , vscode 的一键格式化快捷键为shift + alt + F

           对于mac端, vscode 的一键格式化的快捷键 option + shift + F

有时候,写代码时候没有很好的格式保持习惯,就可以直接快捷键,规避不清晰

定义相关的结构体

主要的是横坐标纵坐标方便后续进行栈的调用

struct Queen {
    int x;
    int y;
};

第一种非递归解法(c++)

由于学校里的机房在csp考试和各类考试中,电脑并没有装python的编译器,所以即便会写python,在考试写完代码后也不方便运行查看结果。所以这里就用C++写,我(小白)对vscode的编译很陌生,所以这里就用的dev c++去写的,我对在dev中代码的调试很不熟练几乎不太会用。

算法思想:非递归法就是从第二行开始,符合的情况就压栈,不符合就继续,一直尝试到最后一行,然后num数量加一,接着就是弹出来,再者去一个个试(隔了一天,这里if else 太多了,我看不清了,不知道啥情况了,脑子看晕了)

#include <iostream>
#include <stack>
#include <cmath>

using namespace std;

struct Queen { // 设立结构体,皇后所用的坐标
    int x;
    int y;
};

// Function to check whether the current queen's position conflicts with the queens in the stack 用来验证这个皇后的位置到底对不对

bool judgeisright(Queen a1, const stack<Queen>& q)
 {
    stack<Queen> temp_stack = q; // Create a copy of the stack to preserve the original
    while (!temp_stack.empty()) { // Loop through all elements in the stack
        Queen temp = temp_stack.top();
        temp_stack.pop();
        // Check for conflicts in rows, columns, and diagonals
        if (a1.x == temp.x || a1.y == temp.y || abs(temp.x - a1.x) == abs(temp.y - a1.y)) {
            return false;
        }
    }
    return true;
}
//只要两个皇后在不同 的行和交叉线上 列 就返回true 说明这个位置是对的

//用于执行和判断有多少种N皇后 的问题
int workout(int N) {
    stack<Queen> all;
    Queen t1;
    t1.x = 1;
    t1.y = 1;
    int num = 0;

    while (t1.x <= N) { // Correct loop condition
        if (t1.y <= N && judgeisright(t1, all)) {
            all.push(t1);
            if (t1.x == N) { // Found one solution
                num++;
                // Backtrack
                t1 = all.top();
                all.pop();
                t1.y++;
            } else { // Move to the first column of the next row
                t1.x++;
                t1.y = 1;
            }
        } else if (t1.y > N) { // If y is out of range, backtrack s
            if (!all.empty()) {
                t1 = all.top();
                all.pop();
            }
            t1.y++;
        } else {
            t1.y++; // Otherwise, move to the next column
        }

        // If backtracking leads to an empty stack, the loop ends
        if (t1.y > N && all.empty()) {
            break;
        }
    }
    return num;
}

int main() {
    int N;
    cout << "Please input the number of Queens you want:" << endl;
    cin >> N;
    cout << "There are " << workout(N) << " ways." << endl;
    return 0;
}

第二种递归的解法(c++)

不断嵌套进行递归,仍然第二行开始,先把新情况的皇后摆放的位置压栈,若符合情况不冲突,就继续行数加一,继续进行递归判断,如果判断下来情况冲突,就弹出来列加一,不断重复,一直x到了N为止,然后num总情况数加一(可能大概就是这样子吧,每一列估计都要去判断一下)

#include <iostream>
#include <stack>
#include <cmath>

using namespace std;

struct Queen {
    int x;
    int y;
};

// Function to check whether the current queen's position conflicts with the queens in the stack
bool judgeisright(const Queen& a1, const stack<Queen>& q) {
    for (stack<Queen> temp_stack = q; !temp_stack.empty(); temp_stack.pop()) {
        Queen temp = temp_stack.top();
        if (a1.x == temp.x || a1.y == temp.y || abs(temp.x - a1.x) == abs(temp.y - a1.y)) {
            return false;
        }
    }
    return true;
}

void workout(int x, int N, stack<Queen>& all, int& num) {
    for (int y = 0; y < N; y++) {
        Queen t1 = {x, y};
        if (judgeisright(t1, all)) {
            all.push(t1);
            if (x < N - 1) {
                workout(x + 1, N, all, num); // Recursive call with reference to all and num
            } else {
                num++; // Found a valid solution
            }
            all.pop(); // Backtrack
        }
    }
}

int main() {
    int N;
    cout << "Please input the number of Queens you want:" << endl;
    cin >> N;
    stack<Queen> all;
    int num_solutions = 0;
    workout(0, N, all, num_solutions); // Pass num_solutions by reference
    cout << "There are " << num_solutions << " ways." << endl;
    return 0;
}

运行结果应该都是没有问题的

  • 5
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值