位运算处理n皇后

位运算的效率要比普通运算快的多,因此我们采用位运算处理数据效率会提高很多。时间复杂度同样是n的n次方,普通方式计算n=14是会用2000ms,而位运算只需300ms。
位运算:
sum=1<<n-1——所有皇后全都放完的状态(例如:n=3,sum为0111,表示三个位置已经全部都用皇后)

1、预处理我们将能放置皇后的地方标为0,不能的标为1。(按照要求看是否需要预处理)

2、dfs(int c,int z,int y,int r)c判断皇后是否放完,z,y处理两条对角线,r为当前行

3、判断所有皇后是否已经放完(即c==sum)。

4、找取第r行的状态,将四者或即为当前行的状态。

5、从第r行开始找0的位置,这里我们将状态按位取反,即查找1的位置(lowbit)。

6、处理下一行。

7、处理下一行时c加上上一行放置皇后时的位置,两个对角线分别z左移1位,y右移一位,r+1。

/*位运算*/
#include<bits/stdc++.h>
using namespace std;
int lowbit(int x)//寻找第一个1的位置
{
    return x&-x;
}
int jud[2002],n;
int sum;
int ans;
//void dfs(int c,int z,int y,int r)
void dfs(int c,int z,int y,int r)//c处理列,z,y处理两条对角线,r为当前行的状态
{
    if(c==sum){ans++;return;}
    int pos=sum&~(c|z|y|jud[r]),p;
    while(pos)
    {
        p=lowbit(pos);
        pos-=p;
        dfs(c+p,(z+p)<<1,(y+p)>>1,r+1);
    }
}
int main()
{
    //int n;
    time_t st,en;
    cin>>n;
    //cout<<sum<<endl;
    sum=(1<<n)-1;
    /*char ch[202];
    for(int a=1;a<=n;a++)
    {
        scanf("%s",ch+1);
        getchar();
        for(int b=1;b<=n;b++)
            if(ch[b]=='.')jud[a]|=(1<<(n-b));
    }*/
    st=clock();
    dfs(0,0,0,1);
    en=clock();
    cout<<ans<<endl;
    cout<<(double)(en-st)<<endl;
    return 0;
}
/*常规方式*/
#include <bits/stdc++.h>

using namespace std;
//不能在同一行,同一列,同一条对角线
//求一共有种情况
const int N=100;
int total;
int n;
int a[N],b[N],c[N],d[N];
void print()
{
    if(total<=2)//保证只输出前三个解,如果解超出三个就不在输出,但后面的total还需要继续
    {
        for(int k=1; k<=n; k++)
        {
            cout<<a[k]<<" ";
        }
        cout <<endl;
    }
    total++;
}
void queen(int i)
{//搜索与回溯主体
    if(i>n)
    {
        //print();//输出函数,自己写
        total++;
        return ;
    }else
    {
        for(int j=1;j<=n;j++)//尝试可能的位置
        {
            if((!b[j])&&(!c[i+j])&&(!d[i-j+n]))//如果没有被占领
            {
                a[i]=j;//标记i排是第j个
                b[j]=i;//宣布占领
                c[i+j]=1;
                d[i-j+n]=1;

                queen(i+1);//进行下一步搜索,下一个皇后

                b[j]=0;
                c[i+j]=0;
                d[i-j+n]=0;
                //回溯
            }
        }
    }
}
int main()
{
    time_t st,en;
    cin>>n;
    st=clock();
    queen(1);
    en=clock();
    cout<<total<<endl;
    cout<<(double)(en-st)<<endl;
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值