码迷,mamicode.com
首页 > 其他好文 > 详细

回溯:八皇后问题(蒟蒻)

时间:2017-12-26 19:51:15      阅读:383      评论:0      收藏:0      [点我收藏+]

标签:攻击   cout   blog   for   main   八皇后   返回   坐标   name   

 
 
 

在一个n×n的棋盘上放置n个国际象棋中的皇后,要求所有的皇后之间都不形成攻击。请你给出所有可能的排布方案数。

输入格式

一个整数n

输出格式

方案数

 

经典的回溯题目。因为对于八皇后问题我们很难找到能够快速得到解的方法(嗯,那些10行写完的速度出门右拐)。所以我们采取枚举法。

皇后的攻击特性是,同行,同列,同一对角线。那么不妨先人为规定第k个皇后在第k行,这样就可以根据皇后的列号求解。

我们先把第1个皇后放在第1行第一列,然后再逐行递归。而这个搜索过程实际是在一棵搜索树上进行的

嗯,树太大不放出来就,百度据说一堆?

然后一个比较关键的问题是如何处理对角线

 技术分享图片

 

就比如说这样一个节点,如果用x表示行,y表示列,这个节点的右对角线就可以用

x-y+n

来表示,因为在这样一条对角线上,所以的点的横纵坐标都满足x-y+n

我们权且把它叫做这个点的右对角线

那么左对角线怎么办呢?

 

 技术分享图片

 

以这个点为例,同样设行用x表示,列用y表示,那么这个点的右对角线就是

x+y

所以在这条对角线上的点的坐标都满足这个式子。

那么接下来的问题就简单了,随便dfs,瞎标记就行了

代码如下:

#include <bits/stdc++.h>

using namespace std;

bool h[70],leftx[70],rightx[70];//h表示列,即不在同一列,leftx表示左对角线,rightx表示右对角线

int n,ans=0;

inline void dfs(int row)//row表示行

{

         if(row==n){

                  

                   ans++;               return;

         }

         for(int i=0;i<n;i++)

         {

                   if(!(h[i]||leftx[row+i]||rightx[row-i+n]))//左对角线上,row+i是一个定值,所以在这条对角线上的数的行列和均为row+i,row-i+n同理

                   {

                            h[i]=leftx[row+i]=rightx[row-i+n]=1;

                            dfs(row+1);//在返回上一层前回溯才能放置新皇后

                            h[i]=leftx[row+i]=rightx[row-i+n]=0;//返回上一层时初始化

                   }

         }

}

int main()

{

         cin>>n;

         memset(h,0,sizeof(h));

         memset(leftx,0,sizeof(leftx));

         memset(rightx,0,sizeof(rightx));

         dfs(0);

         cout<<ans<<endl;

         return 0;

}

 

而在usaco上,还有一道和这个差距不是很大的题,就差了几行代码

 

 技术分享图片

技术分享图片

 

可以看出无非就是按照上面那个思路让在递归的前3层输出所有点的列,开一个数组记录一下列就好了

dfs代码如下:

 技术分享图片

 

回溯:八皇后问题(蒟蒻)

标签:攻击   cout   blog   for   main   八皇后   返回   坐标   name   

原文地址:https://www.cnblogs.com/ywjblog/p/8119587.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!