第一次接触深度优先搜索qwq,小白第一次发文
洛谷题目,原文如下
该题可以看成:每行都有一个棋子,但是每行的棋子它所在的列和它所处对角线上没有其他棋子。
问题难点在于当我们放下第一个,接着放下一个的时候,怎么判断第一个位置对接下来放的棋子的影响。
定义 全局变量total为问题解的个数
先写输出函数(问题分成一个个小块)
题目要求我们输出前三个 每次运行print时total都会计数一次,当total小于3时,顺便输出解的情况
void print()
{
if(total<3)
{
for(int i=1; i<=n; i++)
{
cout<<a[i]<<" ";
}
cout<<endl;
}
total++;
}
下面开始是本题难点了
不妨从上往下看,即从第一行往下摆。
于是可以用一个循环表示从上往下摆,
写函数,queen中i为第i个皇后,或者理解成第i行。
循环j为第j列,从左往右依次试着放下皇后。满足所在列为0(即这一列没有被其他皇后占了位置)(下同)&&主对角线为0&&副对角线为0,即可放下,同时标记,然后摆下一行。
void queen(int i)
{
for(int j=1; j<=n; j++)
{
if((!b[j])&&(!c[i+j])&&(!d[i-j+n]))
{
a[i]=j;
b[j]=1;
c[i+j]=1;
d[i-j+n]=1;//标记
queen(i+1);
}
}
}
数组b为列,c为主对角线,d为副对角线,为啥是c为i+j,d为i-j+n呢?
下图为主对角线表示i+j的结果和副对角线i-j的结果。
然鹅,我们发现i-j<0,所以加n整体都扩大,并不会影响我们判断的。
然后,当i>n时,表明最后一个皇后已经放下了(没有多余的皇后了,呜呜呜,太不容易了QAQ)
我们需要加个判断语句,打印出这种做法。
void queen(int i)
{
if(i>n)
{
print();
return;
}
else
{
for(int j=1; j<=n; j++)
{
if((!b[j])&&(!c[i+j])&&(!d[i-j+n]))
{
a[i]=j;
b[j]=1;
c[i+j]=1;
d[i-j+n]=1;//标记
queen(i+1);
}
}
}
}
是不是就这样结束了?大漏特漏!!!
我们在每次放完一组解的时候要把标记数组(b,c,d)清除干净,放在循环里面就行了。
所以完整的函数代码如下:
void queen(int i)
{
if(i>n)
{
print();
return;
}
else
{
for(int j=1; j<=n; j++)
{
if((!b[j])&&(!c[i+j])&&(!d[i-j+n]))
{
a[i]=j;
b[j]=1;
c[i+j]=1;
d[i-j+n]=1;
queen(i+1);
b[j]=0;
c[i+j]=0;
d[i-j+n]=0;
}
}
}
}
AC完整代码如下
#include <iostream>
using namespace std;
int n,total;
int a[100],b[100],c[100],d[100];
void print()
{
if(total<3)
{
for(int i=1; i<=n; i++)
{
cout<<a[i]<<" ";
}
cout<<endl;
}
total++;
}
void queen(int i)
{
if(i>n)
{
print();
return;
}
else
{
for(int j=1; j<=n; j++)
{
if((!b[j])&&(!c[i+j])&&(!d[i-j+n]))
{
a[i]=j;
b[j]=1;
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()
{
cin>>n;
queen(1);
cout<<total;
return 0;//好习惯从我做起
}
刚接触算法,请各位大佬批评指正QAQ