• 位运算的魅力---N皇后问题


    题目描述

    有一个N*N的棋盘,有些格子可以放置皇后,一个皇后可以对它这一行的位置,这一列的位置,它所在的左对角线和右对角线攻击,这些位置不能放置皇后,一共放置N个皇后,问有多少种放置的方式。

    输入输出格式

    输入格式:

    第一行有一个N。接下来有N行N列描述一个棋盘,“*”表示可放“.”表示不可放。

    输出格式:

    输出方案总数

    solution

     这道题主要考察位运算,例如101001表示这一排第2、4、5个位置可以放置皇后。

    我们用k进制(这里是二进制)来存储状态,这也是状态压缩的基本思想。

    显然每行只能放置一个皇后,我们逐行枚举

     那么我们需要记录四个状态,一是这一行题目给定的状态,二是这一行中有哪些列会被之前摆放的皇后攻击,那么无法再摆放,三是左对角线的影响,四是右对角线的影响,这些状态只用每行一个数字的二进制来存储就行了。

    判断时将这四种情况取并集,再取反,1的位置就成了可以放置的位置,利用lowbit进行DFS即可,具体的实现细节还要看代码

    code

    #include<cstdio>
    #include<iostream>
    #include<string>
    #define re register
    using namespace std;
    int n,all,sta[50],ans;
    string s;
    int lowbit(int x)//找到最右边的1位 
    {
        return x&-x;
    } 
    //取反是补码,与反码不同 ~(3)=-4;
    void dfs(int now,int L,int R,int d)
    {
        if(now==all){ans++;return;} 
        //当now==all的时候,说明全部摆放完毕,ans++ 
        //now表示到这一行的摆放情况,L表示左对角线的情况
        //R表示右对角线的情况,d记录现在在哪一行,
        //sta[d]表示第d行题目的限制条件 
        int pos=all&(~(now|L|R|sta[d])),p; //all是用来限制,把右对角线左移移出去的除掉 
        while(pos)//枚举每个可以放的位置 
        {
            p=lowbit(pos);
            pos-=p;//这一个位置即将枚举,删掉 
            dfs(now+p,(L+p)>>1,(R+p)<<1,d+1);//左对角线对下一行的影响是它的左下角,因此二进制右移
            //右对角线相反,别忘了加上p处放置的棋子的影响 
        }
    }
    int main()
    {
        scanf("%d",&n);
        all=(1<<n)-1;//表示最终状态,比如 n=4 01111 
        for(re int i=1;i<=n;++i)
        {
            cin>>s;
            for(int j=1;j<=n;++j)
             if(s[j-1]=='.')sta[i]|=(1<<(n-j));//对这个数二进制每个位置进行操作 
        }
        dfs(0,0,0,1);//一开始没放,没有任何摆放过皇后限制 
        printf("%d",ans);
        return 0;
    }
  • 相关阅读:
    编程语言
    信安导论2020-2021上第九周总结(20201222)
    链节
    如何学好编程
    第八周学习总结(20201222)信安导论2020-2021上
    实现进制转化伪代码
    fibnacci数列递归实现
    求最大公约数伪代码
    20201332 熟悉编程语言
    如何学好编程(20201332)
  • 原文地址:https://www.cnblogs.com/Liuz8848/p/10796167.html
Copyright © 2020-2023  润新知