深度优先算法
深度优先算法(dfs)是搜索算法中的一种,其基本思想为尽可能的找到树的分支,类似于树的先序遍历,是树先序遍历的推广。
这里以具体实例说明。
八皇后问题是一个以国际象棋为背景的问题:如何能够在8×8的国际象棋棋盘上放置八个皇后,使得任何一个皇后都无法直接吃掉其他的皇后?为了达到此目的,任两个皇后都不能处于同一条横行、纵行或斜线上。八皇后问题可以推广为更一般的n皇后摆放问题:这时棋盘的大小变为n×n*,而皇后个数也变成n。当且仅当n = 1或n ≥ 4时问题有解
对于皇后放置在棋盘产生的影响为行,列,所在格斜线*(后文中斜线均指与主,副对角线平行或共线的直线)*内均不能继续放置皇后,我们可以将它们做出标记
那么知道一点坐标,便可以标识该对角线上所有的点。即pdiag[x-y+6],cdiag[x+y]。
每个格子有一一对应的行,列, (列,行),记作(x,y)试规定以左下角格子为(1,1)向右延伸为(1,2), (1,3),向下延伸为(2,1), (3,1)第可以理解为第y行第x列,那么对角线可以表示为主对角线x-y=0(下图绿线),则副对角线为 x+y = 9,
不难看出,平行或共线于主对角线的方程为x-y = a, a属于[-6,6]且为正整数(注意有序数对(1,8), (8,1)不存在这样的对角线),平行或共线于副对角线的方程x +y = b , b属于(2,16) (类似的(1,1), (8,8)不存在这样的对角线)
将与主对角线平行或共线的直线的记作pdiag-a,与副对角线平行或共线的直线记作cdiag-b,自然的我们考虑映射到数组中作为斜线的标记
p
d
i
a
g
[
a
+
6
]
=
p
d
i
a
g
−
a
,
c
d
i
a
g
[
b
]
=
c
d
i
a
g
−
b
pdiag[a + 6] = pdiag-a, cdiag[b] = cdiag-b
pdiag[a+6]=pdiag−a,cdiag[b]=cdiag−b
还有一点,棋盘为八行八列,放置八皇后,若解,则表明,每列,每行均有皇后,我们考虑放置第x列的皇后,应该放置在行数,若该格点,并未被其他皇后攻击,则放置皇后,并标记各个变量,
#include<stdio.h>
int pdiag[12], cdiag[16], y[9];//如果已被皇后占据,则标记为1即可,y[i]代表第i行是否已存在皇后。
int count;
int queue[9];
void dfs(int x) {
if (x == 9) {//当x等于九,则表明,第八位皇后已放置
count++;
for (int j = 1; j < 9; ++j) {
printf("(%d,%d)\n", j, queue[j]);
}
printf("over\n");
return;
}
for (int i = 1; i < 9; i++) {
if (y[i] == 0 && pdiag[x - i + 6] == 0 && cdiag[x + i] == 0) {
queue[x] = i;//含义为处于第x列的皇后位于第i行。
y[i] = 1, pdiag[x - i + 6] = 1, cdiag[x + i] = 1;
dfs(x + 1);
y[i] = 0, pdiag[x - i + 6] = 0, cdiag[x + i] = 0;//注意,回溯,取消皇后产生的影响。
}
}
}
int main() {
dfs(1);
printf("%d", count);
return 0;
}
运行结果如下:
八皇后是一道比较经典的搜索问题,我们可以通过该题了解深度优先算法的基本模型,对于推广至n皇后问题的求解问题,与本题大同小异,这里就不再赘述,读者可以自行尝试。