数据结构与算法——第6章-树-回溯算法解决八皇后问题(6.19)

一 概述

1
2
3
1.什么是八皇后问题
2.八皇后问题的解决思路
3.示例代码

二 什么是八皇后问题

1
2
3
八皇后问题是以国际象棋为背景的问题:
有八个皇后(可以当成八个棋子),如何在 8*8 的棋盘中放置八个皇后,
使得任意两个皇后都不在同一条横线、纵线或者斜线上。

三 八皇后问题的解决思路

1
2
3
4
5
6
7
8
八皇后问题是使用回溯算法解决的典型案例。算法的解决思路是:
1.从棋盘的第一行开始,从第一个位置开始,依次判断当前位置是否能够放置皇后,
判断的依据为:同该行之前的所有行中皇后的所在位置进行比较,
如果在同一列,或者在同一条斜线上(斜线有两条,为正方形的两个对角线),都不符合要求,继续检验后序的位置。

2.如果该行所有位置都不符合要求,则回溯到前一行,改变皇后的位置,继续试探。
3.如果试探到最后一行,所有皇后摆放完毕,则直接打印出 8*8 的棋盘。
最后一定要记得将棋盘恢复原样,避免影响下一次摆放。

四 示例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#include <stdio.h>
int Queenes[8] = { 0 }, Counts = 0;
int Check(int line, int list) {
int index;
//遍历该行之前的所有行
for (index = 0; index < line; index++) {
//挨个取出前面行中皇后所在位置的列坐标
int data = Queenes[index];
//如果在同一列,该位置不能放
if (list == data) {
return 0;
}
//如果当前位置的斜上方有皇后,在一条斜线上,也不行
if ((index + data) == (line + list)) {
return 0;
}
//如果当前位置的斜下方有皇后,在一条斜线上,也不行
if ((index - data) == (line - list)) {
return 0;
}
}
//如果以上情况都不是,当前位置就可以放皇后
return 1;
}
//输出语句
void print()
{
int line;
for (line = 0; line < 8; line++)
{
int list;
for (list = 0; list < Queenes[line]; list++) {
printf("0");
}
printf("#");
for (list = Queenes[line] + 1; list < 8; list++) {
printf("0");
}
printf("\n");
}
printf("================\n");
}

void eight_queen(int line) {
//在数组中为0-7列
int list;
for (list = 0; list < 8; list++) {
//对于固定的行列,检查是否和之前的皇后位置冲突
if (Check(line, list)) {
//不冲突,以行为下标的数组位置记录列数
Queenes[line] = list;
//如果最后一样也不冲突,证明为一个正确的摆法
if (line == 7) {
//统计摆法的Counts加1
Counts++;
//输出这个摆法
print();
//每次成功,都要将数组重归为0
Queenes[line] = 0;
return;
}
//继续判断下一样皇后的摆法,递归
eight_queen(line + 1);
//不管成功失败,该位置都要重新归0,以便重复使用。
Queenes[line] = 0;
}
}
}
int main() {
//调用回溯函数,参数0表示从棋盘的第一行开始判断
eight_queen(0);
printf("摆放的方式有%d种", Counts);
system("pause");
return 0;
}

大家可以自己运行一下程序,查看运行结果,由于八皇后问题有 92 种摆法,这里不一一列举

五 参考

  • C语言中文网—回溯算法解决八皇后问题