递归回溯法解决八皇后问题
继上次学完函数之后,这次来通过一个实例来加深印象,下面会对其实现过程进行一一剖新,先看一下什么叫“八皇后问题”
具体的算法可以分解为:
像上图中第五行就已经出现了死胡同,这时应该退到第四行,重新安放皇后:
了解了算法流程,下面一步一步来实现:
第一步:
#include <stdio.h> #define QUEEN_NUM 8 int queen[QUEEN_NUM]; // 在第y行上放置皇后 void place(int y); int main(void) { place(0);//首先从第1行开始放置 return 0; } void place(int y) { }
说明一下queen[QUEEN_NUM]数组的含义:
queen[0] = 3代表该皇后y轴的坐标为0,x轴的坐标为3;
queen[1] = 5代表该皇后y轴的坐标为1,x轴的坐标为5;
这样用一个一维数组就可以表达八皇后的问题。
第二步:
#include <stdio.h> #define QUEEN_NUM 8 int queen[QUEEN_NUM]; // 在第y行上放置皇后 void place(int y); // 检测在第y行第x列能否放置皇后 int check(int y, int x); void show(); int main(void) { place(0); return 0; } void place(int y) { if (y == 8)//直接显示八皇后坐标 { show(); return; } int i; for (i=0; i<QUEEN_NUM; i++) // 在第y行的每一列上试探 { if (check(y, i)) { queen[y] = i; place(y+1); // 在下一行放置皇后 } } }
第三步:实现判断是否坐标点能否放置皇后的方法
#include <stdio.h> #define QUEEN_NUM 8 int queen[QUEEN_NUM]; // 在第y行上放置皇后 void place(int y); // 检测在第y行第x列能否放置皇后 int check(int y, int x); void show(); int main(void) { place(0); return 0; } int check(int y, int x) { int i; for (i=0; i<y; i++) { if (queen[i] == x || y - i == abs(x - queen[i]))//如果在同一列,或是斜线上的,则不能存放 return 0; } return 1; } void show() { } void place(int y) { if (y == 8) { show(); return; } int i; for (i=0; i<QUEEN_NUM; i++) // 在第y行的每一列上试探 { if (check(y, i)) { queen[y] = i; place(y+1); // 在下一行放置皇后 } } }
第四步:显示符合八皇后的坐标:
#include <stdio.h> #define QUEEN_NUM 8 int queen[QUEEN_NUM]; // 在第y行上放置皇后 void place(int y); // 检测在第y行第x列能否放置皇后 int check(int y, int x); void show(); int main(void) { place(0); return 0; } int check(int y, int x) { int i; for (i=0; i<y; i++) { if (queen[i] == x || y - i == abs(x - queen[i])) return 0; } return 1; } void show() { int i; static int count = 0;//这个只会初始化一次,所以该函数是有状态的,可以一直累加 printf("the %d solution\n", ++count); for (i=0; i<QUEEN_NUM; i++) { printf("(%d, %d) ", i, queen[i]); } putchar('\n'); } void place(int y) { if (y == 8) { show(); return; } int i; for (i=0; i<QUEEN_NUM; i++) // 在第y行的每一列上试探 { if (check(y, i)) { queen[y] = i; place(y+1); // 在下一行放置皇后 } } }
运行结果:总共92个解
这样打印出来不太直观,实际上可以9空格的样式打印出来:
void show() { int i; int j; static int count = 0;//这个只会初始化一次,所以该函数是有状态的,可以一直累加 printf("the %d solution\n", ++count); for (i=0; i<QUEEN_NUM; i++) { printf("(%d, %d) ", i, queen[i]); } putchar('\n'); for (i=0; i<QUEEN_NUM; i++) // 行 { for (j=0; j<QUEEN_NUM; j++) // 列 { if (queen[i] == j)//代表这一个坐标为皇后,就输出Q printf("Q "); else printf("x ");//代表这一个坐标没有皇后,就输出X } putchar('\n'); } }
输出如下:
好了,今天的练习到此,至于怎么回溯的,需看代码仔细体会下。