八皇后(暴力DFS)

本人是个弱鸡,今天第一次刷搜索和回溯就遇到了这道经典八皇后,思路很简单,实际操作不容易啊。二话不说先来看题。

神奇的题目:

P1219 八皇后

题目描述

检查一个如下的6 x 6的跳棋棋盘,有六个棋子被放置在棋盘上,使得每行、每列有且只有一个,每条对角线(包括两条主对角线的所有平行线)上至多有一个棋子。

上面的布局可以用序列2 4 6 1 3 5来描述,第i个数字表示在第i行的相应位置有一个棋子,如下:

行号 1 2 3 4 5 6

列号 2 4 6 1 3 5

这只是跳棋放置的一个解。请编一个程序找出所有跳棋放置的解。并把它们以上面的序列方法输出。解按字典顺序排列。请输出前3个解。最后一行是解的总个数。

//以下的话来自usaco官方,不代表洛谷观点

特别注意: 对于更大的N(棋盘大小N x N)你的程序应当改进得更有效。不要事先计算出所有解然后只输出(或是找到一个关于它的公式),这是作弊。如果你坚持作弊,那么你登陆USACO Training的帐号删除并且不能参加USACO的任何竞赛。我警告过你了!

输入输出格式

输入格式:

 

一个数字N (6 <= N <= 13) 表示棋盘是N x N大小的。

 

输出格式:

 

前三行为前三个解,每个解的两个数字之间用一个空格隔开。第四行只有一个数字,表示解的总数。

 

输入输出样例

输入样例#1: 复制
6
输出样例#1: 复制
2 4 6 1 3 5
3 6 2 5 1 4
4 1 5 2 6 3
4

说明

题目翻译来自NOCOW。

USACO Training Section 1.5

思路:

看到这道题目首先想到的是用循环一个个套,简称真.暴力枚举,然后看一眼题目名称,额,八皇后!八个循环!成功GG。

接下来就想到了刚学的搜索与回溯。就尝试往这上面走,我们很容易想到要使皇后不互相攻击,就要保证她的行列斜边方向都不能有子。

自然容易想到用二维数组,然后请仔细读题,行数是按照顺序的,你只用输出列数就好了,所以没有必要开二维数组。

然后我们需要知道满足条件,观察图,易知行数已经避开,每个皇后下方都不能有另一个皇后,其次左斜线上的每个格子的行列和相等,右斜线的每个格子上

的行列差相等。很容易就能列出条件。但注意:行列之差可能是负数,所以将你的整个斜线向右偏移,保证不出现负数数组。其次要还原现场,定义bool数组

来实现。注意:一定要在皇后没有占领这个格子才能实现。然后他只让我们输出三个步骤所以我们在函数中首先用个循环控制输出。记住:一定要保证前面所

有行都已经搜索过才能将方案+1,再转入第二种搜索,所以你得保证你的步骤挨到了行数的下一个。

然后就可以看代码了。

#include<iostream>
#include<cstdio>
using namespace std;
int n,a[14],g;
bool b[14],c[14],d[14];
void dfs(int);
int main()
{
 cin>>n;
 dfs(1);
 cout<<g;
 return 0;
}
void dfs(int step)
{
 if(step==n+1)
 {
  g++;
     if(g<=3)
    {
  for(int i=1;i<=n;i++)
  {
     cout<<a[i]<<" ";
  }
  cout<<endl;
    } 
    }
 else
 {
  for(int i=1;i<=n;i++)
  {
   if(!b[i]&&!c[i+step]&&!d[step+n-i])
   {
    a[step]=i;
    b[i]=true;
    c[i+step]=true;
    d[n-i+step]=true;
    dfs(step+1);
    b[i]=false;
    c[i+step]=false;
    d[n-i+step]=false;
   }
  }
 }
}

然而还是错了,原因在哪呢?问题出现在数组太小了。既然你都将斜线整体向右平移,那么原来的数组还容得下吗,显然不能。俗话说得好——数组开大,多

多益善。

正解:

#include<iostream>
#include<cstdio>
using namespace std;
int n,a[14],g;
bool b[14],c[30],d[30];
void dfs(int);
int main()
{
 cin>>n;
 dfs(1);
 cout<<g;
 return 0;
}
void dfs(int step)
{
 if(step==n+1)
 {
  g++;
     if(g<=3)
    {
  for(int i=1;i<=n;i++)
  {
     cout<<a[i]<<" ";
  }
  cout<<endl;
    } 
    }
 else
 {
  for(int i=1;i<=n;i++)
  {
   if(!b[i]&&!c[i+step]&&!d[step+n-i])
   {
    a[step]=i;
    b[i]=true;
    c[i+step]=true;
    d[n-i+step]=true;
    dfs(step+1);
    b[i]=false;
    c[i+step]=false;
    d[n-i+step]=false;
   }
  }
 }
}

完结撒花!!!