N皇后问题

51. N 皇后 - 力扣(LeetCode) (leetcode-cn.com)icon-default.png?t=LA92https://leetcode-cn.com/problems/n-queens/submissions/

目录

方法一:采用深度探索与递归的方法进行选择

方法二:使用数字的位信息


方法一:采用深度探索与递归的方法进行选择

可取之处是将判断与遍历拆分成为两个子函数,这样有利于增加可读性。

同时使用一维向量xi记录第几行的皇后放在第几个位置上。

同时应该注意关于数据结构(队列,栈,向量,哈希表)作为参数传入函数时,

如果要求在void函数里面对上述类型的参数进行修改,要加”&“(比如以前的深度遍历等要对结果进行改变,所以要加”&“)

但如果不要求在void函数里对上述类型的参数进行改变,则不加”&“,表示复制一份该参数传进函数,这样你如何对函数里的参数进行改变都不影响我原参数,因为你改变的只是我的复制品。这种情况适用于该题目这种会有很多种可能的结果,但是在分叉处我要下面两条路都要走,如果以第一种方式传入参数,那么会对原参数进行改变,这样你走完第一条路你把分叉处的参数都改变了,我怎么从原来的参数走第二条路!所以要使用第二种传入参数的方式,这样相当于复制了一份传入子路的函数,同时在这条路走完不影响另一条子路的前进。

class Solution {
public:
void play(vector<vector<string>>&result, int n, vector<int>xi,int i){//i表示当前处理第几行
    for(int j=0;j<n;j++){
        if( judge(i,j,xi) ){
            xi[i]=j;
            if(i==n-1){
                vector<string>one(n);
                for(int p=0;p<n;p++){
                    string chuan(n, '.');
                    chuan[xi[p]]='Q';
                    one[p]=chuan;
                }
                result.push_back(one);
                return;
            }
            play(result,n,xi,i+1);
        }
    }
}

bool judge(int i,int j,vector<int>xi){
    for(int p=0;p<i;p++){
        if( (j==xi[p]) || (abs(xi[p]-j)==abs(p-i))){return false;}
    }
    return true;
}

    vector<vector<string>> solveNQueens(int n) {
        vector<int>xi(n);
        vector<vector<string>>result;//每一行里面都表示一种排列方案
        play(result,n,xi,0);
        return result;
    }
};

方法二:使用数字的位信息

对于每一行放了一个皇后,对后面产生的影响包括“左斜线限制,右斜线限制,列限制”

通过数字的为信息表示禁止位置的变化

如果当前行放了皇后,那么算上当前行以及前面行的左限制为“(left|a)<<1)”,同理右限制“(right|a)/2”,列限制为“down|a”。

写一个二进制表示为n位“1”的int数据,limit的作用是限制位数,它从始至终都是n位1。防止左移啥的位数超出限制。

class Solution {
public:
void bianli(vector<vector<string>>&result,int limit,int left,int right,int down,int n,vector<int>one,int i){
    if(down==limit){
        vector<string>oneCase;
        for(int i=0;i<n;i++){
            string hang(n,'.');
            hang[one[i]]='Q';
            oneCase.push_back(hang);
        }
        result.push_back(oneCase);
        return;
    }
    int pos=limit&(~(right|left|down));//pos中写0的是不行的限制,只有为1的才能填写。注意取反过了所以为1的位置是可以允许的
    while(pos!=0){
        int a=pos&((~pos)+1);//a提取出最后一个1
        pos=pos-a;
            int suanweizhi=a;
            int lie=0;
            while(suanweizhi!=0)
            {suanweizhi=suanweizhi/2;lie++;}
            //cout<<lie<<endl;
            one[i]=lie-1;
        bianli(result, limit , ((left|a)<<1) , ((right|a)/2) , (down|a) , n , one , i+1);
    }
}


//主函数
    vector<vector<string>> solveNQueens(int n) {
        vector<vector<string>>result;//if(n>31){return result;}
        vector<int>one(n);
        int limit=1;
        for(int i=0;i<n-1;i++){
            limit=1+(limit<<1);
        }//写一个二进制表示为n位“1”的int数据,limit的作用是限制位数,它从始至终都是n位1
        int left=0;int right=0;int down=0;//分别表示左斜线限制,右斜线限制,列限制
        bianli(result,limit,left,right,down,n,one,0);
        return result;
    }
};

在解答过程在“one[i]=lie-1;”曾写为“one.push_back(lie-1);”但是这样带来的问题是while里面每一次都会在后面写上新的,逻辑出现错误,所以应该改变第i位的值而不是每次都添加。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值