Codevs 1295 N皇后问题

题目描述 Description

在n×n格的棋盘上放置彼此不受攻击的n个皇后。按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。n后问题等价于再n×n的棋盘上放置n个皇后,任何2个皇后不妨在同一行或同一列或同一斜线上。

输入描述 Input Description

给定棋盘的大小n (n ≤ 13)

输出描述 Output Description

输出整数表示有多少种放置方法。

样例输入 Sample Input

8

样例输出 Sample Output

92

数据范围及提示 Data Size & Hint

n<=13

(时限提高了,不用打表了)


八皇后问题是一个经典的深度优先搜索问题,在此说一下这个题的难点和剪枝。

思考

首先,皇后的攻击范围是米字型,也就是四条互不平行的直线,所以我们想到使用四个布尔数组
来表示皇后能够攻击到的区域。

具体怎么实现呢?

因为皇后能够攻击一整行和一整列,所以我们只需要用”bool hang[15],lie[15];”这样来记录就好了。
难点来了,斜向怎么实现呢?

让我们观察一个6*6的棋盘:

x+y123456
1234567
2345678
3456789
45678910
567891011
6789101112

发现了吗?从右上到左下↙的这条线中,所有x+y的值都是一样的。
例如,(1,3)=4;(2,2)=4;(3,1)=4;
这样我们就解决了一条对角线,开一个”bool xian[30];”用x+y的值表示数组下标。
例如,我们在(4,5)放置了皇后,那么就让”xian[9]=true;”

另一条对角线怎么办呢?

我们似乎无法从表中得出什么规律了,但我们可以为每一条↘对角线标上一个序号。
将最长的那条标为1,然后以横行为起点的线依次标为2,3,4… ,以竖列为起点的依次标为2+n,3+n,4+n…
突然发现,以横行为起点的标号就是x-y+2啊。
get√


贴码

#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<cstdlib>
#include<cmath>
using namespace std;
const int maxn=15;
int m,n,k,tot,ans,day,year;
int a[maxn];
bool hang[maxn],lie[maxn],xian[maxn<<2],xian2[maxn<<2];
void f(int k)
{
    if(k==n)
    {
        ans++;
        /*if(tot<3)
        {
            for(int i=1;i<=n;i++)
                printf("%d ",a[i]);这一段是过洛谷P1219加的代码。
            puts("");
        }

        tot++;*/
        return;
    }
    for(int i=1;;i++)
    {
        if(hang[i]==false)
        {
            hang[i]=true;
            for(int j=1;j<=n;j++)
            {
                if(lie[j]==false&&xian[i+j]==false)
                {
                    bool mmp=false;int ll;
                    if(j>=i)
                    {
                        ll=j-i+2;
                        if(xian2[ll]==false)
                        {
                            xian2[ll]=true;
                            mmp=true;
                        }
                    }
                    else 
                    {
                        ll=i-j+n+1;
                        if(xian2[ll]==false)
                        {
                            xian2[ll]=true;
                            mmp=true;
                        }
                    }
                    if(mmp)
                    {
                        lie[j]=true;xian[i+j]=true;
                        //printf("%d,%d\n",i,j);//调试时这样写其实很方便
                        a[k+1]=j;//P1219
                        f(k+1);
                        lie[j]=false;xian[i+j]=false;
                        xian2[ll]=false;    
                    }

                }

            }
            hang[i]=false;
            break;//这一句可以让你的DFS快N倍
        }

    }
    return;
}
int main()
{
    scanf("%d",&n);
    f(0);//从一个皇后都没有放开始搜
    printf("%d",ans);
    return 0;
}

然而我们无论我们怎样优化,也没法做到十五皇后不超时QAQ

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值