本来想刷kuangbin专题的……结果专题一第一题就卡了,看到推荐说可以先复习一下八皇后问题,发现太久不写搜索我已经是屑了orz
题意:在N*N的棋盘上,给出N个棋子,同行、同列、同对角线只可以放一个,问有多少种不同的排列方法。
要用搜索我们都知道,但是把什么设为dfs的参数呢?
最开始设置的是x,y,rest,标记当前位置和剩余棋子数量,但是把我自己绕进去了,搞了半天也没法保证全部扫到,并且写的时候忽略了对角线是有两个方向的。在这道题里面,行列均唯一,所以其实关于定位的参数只需要x,y中一个就可以,如果有两个到时候还要分八个方向移动(但是其实没有必要)。关于对角线的判断,最开始我是用while一遍遍扫,也非常麻烦。
看了题解之后觉得处理方法很巧妙:
- 只记录行,不需要rest,用行兼顾rest的作用(逐行扫,扫到n行时即完成)
- 用三维数组mark[3][],第一维分别表示两种对角线和列
- 对角线的规律:主对角线行列差相同(为了排除负数+N),次对角线行列和相同。
最后,太久不写,我自己搞的时候回溯的位置搞得乱七八糟,仔细品味一下这里,我们是先判断当前位置是否合法(dfs的时候不判断,递归进来再判断),假如合法,先改变标记(标记为已经走过),向下dfs,再抹去标记。在这里,下一位置的试探是通过i的循环控制的,我们相当于定住了行,改变i来在列之间移动,兼用mark[3][]判断这一位置是否合法。
P.S.1000MS 要预处理
#include <bits/stdc++.h>
using namespace std;
int N, tans;//N <= 10 N*N棋盘上N个皇后
int mark[3][25], ans[11];
void dfs(int row)
{
if(row == N+1)
{
tans++;
return;
}
for(int i = 1;i <= N;i++)
{
if(mark[0][row - i + N] == 0 && mark[1][i] == 0 && mark[2][i + row] == 0)
{
mark[0][row - i + N] = mark[1][i] = mark[2][i + row] = 1;
dfs(row+1);
mark[0][row - i + N] = mark[1][i] = mark[2][i + row] = 0;
}
}
}
int main()
{
for(int i = 1;i <= 10;i++)
{
tans = 0, N = i;
memset(mark, 0, sizeof(mark));
dfs(1);
ans[i] = tans;
}
while(scanf("%d", &N) && N != 0)
{
printf("%d\n", ans[N]);
}
return 0;
}