这题好像是第一次接触dfs,所以注释很详细了。
再贴个老师的模板吧,初次接触我感觉看看模板挺有用的
模板注意事项当然还原也不是必须的步骤,要自己去看题意还需不需要你访问访问过的地方,如果需要就不用还原了。
题解
/*本题要打表记录每种可能,不然每dfs一次算一次会超时,打表法应用*/
#include <iostream>
#include <stdio.h>
#include <cstring>//memset函数头文件
#include <cmath>
const int maxn = 11;
int map[maxn];//需要注意的是map[k]=j。表示的是第k个棋子放在第j列.
/*k为第几个棋子,j为第几个棋子放的列数*/
int visited[maxn];//用於标记某一列是否已经访问过
int result[maxn];//打表,保存各个结果
int flag;
int ans;
int n;
using namespace std;
void dfs(int k) {
if (k == n + 1) {//如果k已经达到n+1.表示所有棋子已经摆放完毕
ans++;//棋子成功拜访的方案数+1
return;
}
int i;
int j;
for (i = 1; i <= n; ++i) {//遍历所有列
if (visited[i] == false) {//如果该列没有被访问
map[k] = i;//尝试将第k个棋子放在第i列(第k个旗子肯定是在第k行的)
flag = true;//置尝试标记为成功
for (j = 1; j <= k - 1; ++j) {//遍历之前的k-1个棋子
/**
* 如果他们在同一斜线上(在这种实现方式中,他已经确保了没一个棋子肯定会与其他棋子在不同行、不同列.
* 这时候我们只需要判断一下它们是否在同一斜线上即可)
*/
if (abs(map[k] - map[j]) == abs(k - j)) {
flag = false;//将标记设置为false
break;/*换下一列*/
}
}
if (flag == 1) {//如果flag为true,表示第k个棋子可以摆放成功
visited[i] = 1;//将第i列标记为已经访问过
dfs(k + 1);//开始拜访第k+1棋子
visited[i] = 0;//将第i列重新标记为未访问过.用于其他情况
}
}
}
}
int main()
{
while(scanf("%d",&n)!=EOF)
{ memset(visited,0,sizeof(visited));
flag=0;
ans=0;
if(n==0)
break;
dfs(1);
printf("%d\n",ans);
}
return 0;
}