题目是这样的:
题目要求我们找到一系列的排列方式,要求是此位置的每一行每一列且两条对角线的范围内只能存在一个棋子,棋盘的规模是n*n。
可以知道这样的题目可以使用dfs求出。可光知道dfs还不行,还要能够根据题目更改细节。此题我们不必要死板的用一个数组一个一个位置的去标记位置不可用。我试过,答案是对的,超时了……而且那样内存占用也会相对较多。所以我们可以该换一下思维,你想,它要求的是行列和对角线不能用,那干脆就直接使用几个数组用来标记行、列和对角线。我们可以使用某些数使得这几个数组中的下标拥有唯一性,也就是行、列和对角线都独有一个位置。这样就可以很好的用以标记一使用的行列对角线了。其他的就是正常的dfs了,要记得回溯嗷。
代码如下:
#include <iostream>
#include <cmath>
#include <memory.h>
#include <algorithm>
using namespace std;
int ans[115]={0},n,k;
int a[110],b[110],c[110],d[110],m,l;//用a数组记录皇后可以占领的位置,b数组表示已被使用过的列,c,d数组表示两个对角线
void dfs(int ci,int cnt)//ci为行,cnt记录皇后占领位置的个数
{
if(cnt==n)
{
if(m>=3)//只需要求出前三种
{
m++;return;//持续计数
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(a[j]==i)//从记录的a数组中把找出来的点按顺序放入答案数组中
ans[l++]=j;
m++;//计数
return;
}
for(int i=1;i<=n;i++)
{
if((!b[i])&&(!c[ci+i])&&(!d[ci-i+n]))
{
a[i]=ci;
b[i]=1;
c[ci+i]=1;
d[ci-i+n]=1;//用几个数组统一表示行和列和对角线,对比在”地图“中一个个位置去标记,大大节省了时间复杂度
dfs(ci+1,cnt+1);
a[i]=0;
b[i]=0;
c[ci+i]=0;
d[ci-i+n]=0;//回溯
}
}
}
int main()
{
scanf("%d",&n);
dfs(1,0);
for(int i=0;i<l;i++)
{
printf("%d ",ans[i]);
if((i+1)%n==0)
printf("\n");
}
cout <<m;
}
题目说是只需要前3个答案序列,所以根据题目更改细节,这样就少占用了很多内存。
其中代码中代表对角线数组,因为ci-i在for循环中会出现小于0的情况,而这种情况可以推出最大也就是当i=n而ci=1,那么就是1-n,所以我们直接给它加个n,数组开大点就好了,没什么影响。