目录
错误写法(可跳
DFS-剪枝
代码
思路二: 原始解法
错误写法(可跳
看到这道题,我想这不还是n个数的全排列的问题么?也就是把数字变成了字符,一些输出格式上的变化。于是就在原有代码上修改一下应该就行。
我的思路就还是path存有可能的排序路径,但是输出的时候要输出字符,且为棋盘格的二维数组形式,因此添加了两层for循环嵌套,并用if语句判断 path[i]==j ,说明此处放皇后Q,符合输出格式。
代码
#include<iostream>
using namespace std;
const int N=12;
int n;
int path[N];
bool st[N];void dfs(int x)
{if(x==n){for(int i=0;i<n-1;i++)//只判断了相邻两个皇后是否处于同一斜线{//由于数组会索引到i+1 因此第二个表达式应该是i<n-1if(path[i]-path[i+1]==1 || path[i]-path[i+1]==-1)return;}for(int i=0;i<n;i++){for(int j=0;j<n;j++){if(path[i]==j){printf("Q");}else{printf(".");}}puts("");}puts("");return;}for(int i=0;i<n;i++){if(!st[i]){st[i]=1;path[x]=i;dfs(x+1);st[i]=0;}}
}
int main()
{scanf("%d",&n);dfs(0);return 0;
}
这里错误的原因在于,我通过在得到一种答案输出之前,
for(int i=0;i<n-1;i++)//只判断了相邻两个皇后是否处于同一斜线{if(path[i]-path[i+1]==1 || path[i]-path[i+1]==-1)return;}
判断相邻两个皇后的数字相差不能是1或-1,也就是限制了相邻两个皇后的位置不能是对角线或者副对角线的关系。
但是题目要求的是任何两个皇后都不能呈对角线或副对角线的关系。因此这样的写法是不符合题意的。虽然有些情况下会输出正确结果,但是正确率极低。只能说是忘记模板的话能蹭一点点分😂。
ok正文开始~
DFS-剪枝
我们观察到这是一个在 n个数的全排列 框架之下的问题。我们需要注意的就是
1.输入输出格式是字符。因此我们考虑把原来的path存储答案的序列改为 char 类型的 g[N][N] 二维数组,也方便符合条件的输入输出。
首先要将二维棋盘格初始化全为 '.' ,利用两层for循环嵌套。输出的时候可以直接输出 g[i] 表示输出一行的字符串
其次在dfs恢复现场的时候, g[u][i]='.' 也要恢复。因为我们在搜索过程中修改了棋盘的状态。当我们从一个节点回溯到它的父节点时,我们需要把棋盘恢复到父节点的状态,以便于搜索父节点的其他子节点。
在单纯的数字全排列问题中我们会不断地在同一位置尝试不同的数字,因此前一个数字会被后一个数字覆盖。这个过程并不需要我们手动去恢复,因为每次尝试新的数字时,旧的数字自然就被"覆盖"了。
2.任意两个皇后都不能处于同一行、同一列或同一斜线上
这是区别于模板的最主要的题设。有了这些限制,我们就要多加限制条件,去掉一些不满足条件的答案,称“剪枝”。
由于我们是以行为基准,每一次递归调用dfs(u+1)都会使得行数u增加1,这样就保证了每一行只有一个皇后。因此,我们并不需要额外的数组来检查是否有多个皇后在同一行。我们需要另外定义col数组表示列,dg数组表示对角线,udg数组表示主对角线。
col数组的坐标直接是 i 表示列,那么如何表示对角线呢?
在一个二维平面上,一条直线的斜率和截距可以唯一确定这条直线。在这个问题中,我们的直线其实就是棋盘上的对角线,斜率固定为1或-1(因为对角线的斜率是固定的),所以我们只需要找到一个唯一的截距就可以确定一条对角线。
代码中u就表示行,i 表示列。由此得出dg udg 的下标表示
for(int i=0;i<n;i++){if(!col[i] && !dg[u+i] && !udg[n-u+i]){g[u][i]='Q';//用u来表示行,变化的是第u行中的某个元素col[i]=dg[u+i]=udg[n-u+i]=1;dfs(u+1);//通过递归确保了每一行放一个皇后g[u][i]='.';//恢复现场col[i]=dg[u+i]=udg[n-u+i]=0;}}
代码
#include<iostream>
using namespace std;
const int N=12;
int n;
char g[N][N];
bool col[N],dg[N],udg[N];void dfs(int u)
{if(u==n){for(int i=0;i<n;i++){puts(g[i]);}puts("");return;}for(int i=0;i<n;i++){if(!col[i] && !dg[u+i] && !udg[n-u+i]){g[u][i]='Q';//用u来表示行,变化的是第u行中的某个元素col[i]=dg[u+i]=udg[n-u+i]=1;dfs(u+1);//通过递归确保了每一行放一个皇后g[u][i]='.';//恢复现场col[i]=dg[u+i]=udg[n-u+i]=0;}}
}
int main()
{scanf("%d",&n);for(int i=0;i<n;i++){for(int j=0;j<n;j++){g[i][j]='.';}}dfs(0);return 0;
}
思路二: 原始解法
先放代码,思路之后回来补写,,
#include<iostream>
using namespace std;
const int N=12;
int n;
char g[N][N];
bool row[N],col[N],dg[N],udg[N];void dfs(int x,int y,int s)
{if(y==n)//该行已经遍历完了,因此列标要重新从0开始,行数+1{y=0;x++;}if(x==n)//当行数也遍历完{if(s==n)//先判断皇后数量是否符合题意{for(int i=0;i<n;i++)//满足条件说明得一个答案{puts(g[i]);}puts("");}return;}//不放皇后dfs(x,y+1,s);//如果满足这些条件才会放皇后if(!row[x] && !col[y] && !dg[x+y] && !udg[x-y+n]){g[x][y]='Q';row[x]=col[y]=dg[x+y]=udg[x-y+n]=1;dfs(x,y+1,s+1);row[x]=col[y]=dg[x+y]=udg[x-y+n]=0;g[x][y]='.';}
}
int main()
{scanf("%d",&n);for(int i=0;i<n;i++){for(int j=0;j<n;j++){g[i][j]='.';}}dfs(0,0,0);//从第0行第0列即左上角开始搜,此时皇后数量为0return 0;
}
先写到这咯,状态不太好,下午先休息了emmm
有问题欢迎指出!!一起加油!!