秋天的第一篇博客(枝剪)

HDU2553皇后问题

本题此次采用搜索思想,因为题目中要求N<=10所以BFS和DFS姑且还在时间复杂度允许范围内。

算是个DFS练习吧。

题目分析:
从第一行开始安放皇后,产生node1,此后第二场再按要求安放,产生node2,以此类推会出现符合题意的若干答案。
根据题目要求,皇后之间不能同行同列同斜线,所以假设新皇后的坐标位置为(x,y)原本皇后坐标为(i,j)有如下关系。
1.因为不同行不同列,所以对应x=i和y=j是不行的。
2.因为不同斜线,所以abs(i-x)=abs(j-y)也是不行的
满足如上俩个要求就能安放新的皇后。

重点:当我们在不断产生node的同时我们也会发现有些支路还没到最后一步就已经无法再产生node了,这时我们就要进行“枝剪”,把已经没有产生正确答案可能的支路给减掉。

关键点就是剪掉支路。
DFS代码

/*n皇后问题*/
#include <bits/stdc++.h>
using namespace std;

int ans,n,col[12]={0};

bool check(int r,int l)
{
     for(int i=0;i<r;i++)
     {
         if(col[i]==l||abs(col[i]-l)==abs(i-r))
           {
               return false;
           }
     }
     return true;
}

void DFS(int r)
{
    if(r==n)
    {
        ans++;/*说明已经有一条路走到了尽头,我们要结束他了,并且还要把他算作一种答案*/
    }
    else
    {
        for(int i=0;i<n;i++)/*一共有n列*/
        {
            if(check(r,i))
            {
                col[r]=i;
                DFS(r+1);
            }
        }
    }
}



int main()
{
    int t;
    for(cin>>t;t;t--)
    {
        memset(col,0,sizeof(col));
        ans=0;
        cin>>n;
        DFS(0);/*从第0行开始安放皇后*/
        cout<<ans<<endl;
    }
    return 0;
}

解释一下
check这里
if(col[i]==l||abs(col[i]-l)==abs(i-r))
其实就是你要在第r行安防皇后,你需要遍历0到r-1行是否都满足条件
而我们在DFS中的这一步 col[r]=i;知道在之前安放的过程中入过第r行的第i列满足条件我们就将其标记在col数组中,这样col[i]就是这一行符合要求的那一列的列数。
DFS这里
我们最后如果已经安排到了r=n的时候,因为r是从0开始的,我们能够确认所有的皇后都安放完毕,所以可以结束递归并且记录这一种状态(ans++)

如果没有满足r=n的话就继续对第R行来安放皇后,皇后共有n列可以选择所以我们要for(int i=0;i<n;i++)也就是把这一行的所有列都试试看。然后这一行结束了再继续向下一行探索 DFS(r+1);

主函数这里
为了保证正确性,每一次都要清零。

那么枝剪体现在了那里呢?
for循环中如果连续n次都判定if(false)那么这条路就到此结束了,也不会继续执行DFS(r+1)

为什么看上去有些不像DFS呢
的确,,,,这个一层一层搜索的时候会先在这一层找到"正确答案"然后再继续往下走,而且也没有返回节点这一操作。一个是因为枝剪,另一个就是因为这个题实际上是在一步步找最终状态,而不是找到一个值就结束了,跟何况这个最终状态还是多样的,所以必须遍历完所有的可能,这就感觉不像是DFS,其实BFS也可以写只是因为代码写来起来比较烦我没写。

明天写迭代加深搜索的埃及分数问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值