本题是一道dfs的题目()()感觉主要的困惑点在于对角线的判断(我刚开始还想遍历)
题目:
题目很简短,清晰易懂,就是要找到全部的能使n个棋子在不同行不同列并且也不会在同一对角线或与对角线平行的线上的排列方法,并输出按字典序排列的前三种方法
乍一看,最先想到的就是放个二维数组每次遍历,但又会很快的叉掉(
于是,我们采取搜寻列、两个方向的对角线的方法而不是遍历数组来判断当前位置能否放棋子
代码如下:
#include <stdio.h>
int n = 0; //用于记录棋盘大小
int col[14] = { 0 };//用于判断当前列是否有棋子
int left_diag[39] = { 0 };//用于判断次对角线(对于某个位置来说)
int right_diag[26] = { 0 };//用于判断主对角线(对于某个位置来说)
int ans[15] = { 0 }; //答案数组
int count = 0; //记录摆放数;
/*对于left_diag与right_diag这两个数组的运作方式的解答:
* 若有棋盘
* 1 2 3 4
* 1 0 0 0 0
* 2 0 0 0 0
* 3 0 0 0 0
* 4 0 0 0 0
* 不难看出,对于一个向右下的对角线,其上元素的行指标减列指标总为定值
* 那么,对于一个确定的棋盘,该方向对角线的‘定值’的最大值会在最左边那条对角线取得,即行指标为n,列指标为1,定值也就是n-1
* 而在右边的对角线,该定值为负,所以我们需要给一个偏移量,让所有的定值映射到正数,即+n 处理来标记每条对角线
* 于是,我们的right_diag数组,应该给26的大小
* 类似的,我们也可以得出left_diag应该给出39的大小;
*/
//核心:深搜
void dfs(int row)
{
//搜到一种摆放方式
if (row == n + 1)
{
//计数器+1
count++;
//打印前三个摆放方式
if (count <= 3)
{
for (int i = 1; i < n + 1; i++)
{
printf("%d ", ans[i]);
}
printf("\n");
}
return;
}
//搜索每一列是否可能有答案
for (int i = 1; i < n + 1; i++)
{
//如果当前列没有棋子并且两个方向的对角线也没有棋子
if (!col[i] && !left_diag[i + row] && !right_diag[row - i + n])
{
//标记
col[i] = 1; left_diag[i + row] = 1; right_diag[row - i + n] = 1;
//放入答案
ans[row] = i;
//搜索下一行
dfs(row + 1);
//清除标记
col[i] = 0; left_diag[i + row] = 0; right_diag[row - i + n] = 0;
//清除答案
ans[row] = 0;
}
}
return;
}
int main()
{
scanf("%d", &n);
dfs(1);
printf("%d", count);
return 0;
}
最后,附上AC!!!