引用这首诗为了引出一个算法,叫做回溯法.
什么是回溯,通俗的解释就是当你发现自己当初的选择是错误的时候,用时光机把你送回到做选择的那一天,让你重来一次.想一想如果高考时给你这样的福利,岂不是美滋滋?
一下关于八皇后的解法,就是利用了回溯法.
首先做一个最简单的说明,因为八个皇后互相之间都攻击不到,即不能在同一行,同一列,同一对角线.所以我们每一次只需要确定第一行的皇后的位置就可以.
先在第一行的第一列放置一个皇后,此时它一定是合理的位置.但检测的
步骤不能省.
具体的检测逻辑是,把我们刚刚放置皇后的这一行之前的皇后全部拿过来攻击它,如果攻击不到,就是合法的,我们就继续放下一行.否则,我们就换一列放置,并重新检测.
如果一路检测下来都是合格的,那么第八个皇后放完,我们就得到了第一个解.然后变动上一步的位置继续检测,知道所有的解去不求出.
伪代码更容易理解:
# define _CRT_SECURE_NO_WARNINGS
# include<cstdio>
# include<cstdlib>
# include<cmath>
int 每行中皇后所处的列数[8] = { 0 },合法的摆放方式; //皇后在每行中所处的列数
void print_map()
{
printf("\n\n\t\t=================第%d种摆放方法=================", 合法的摆放方式);
int 行数, 列数;
for (行数 = 0; 行数 < 8; 行数++)
{
printf("\n\t\t\t\t");
for (列数 = 0; 列数 < 每行中皇后所处的列数[行数]; 列数++)
{
printf("□");
}
printf("■");
for (列数 = 每行中皇后所处的列数[行数] +1; 列数 < 8; 列数++)
{
printf("□");
}
}
}
//检测当前位置是否合法
int check_positon_valid(int 待检测位置行数, int 待检测位置的列数)
{
int 已经就位的皇后所处的列数;
int 已经就位的皇后所处的行数;
for (已经就位的皇后所处的行数 = 0; 已经就位的皇后所处的行数 < 待检测位置行数; 已经就位的皇后所处的行数++)
{
已经就位的皇后所处的列数 = 每行中皇后所处的列数[已经就位的皇后所处的行数];
if (待检测位置的列数 == 已经就位的皇后所处的列数
|| 待检测位置行数 + 待检测位置的列数 == 已经就位的皇后所处的行数 + 已经就位的皇后所处的列数
|| 待检测位置行数 - 待检测位置的列数 == 已经就位的皇后所处的行数 - 已经就位的皇后所处的列数)
{
return 0;
}
}
return 1;
}
void put_queen(int 即将放置的行数)
{
int 即将放置的列数;
for (即将放置的列数 = 0; 即将放置的列数 < 8; 即将放置的列数++)
{
if (check_positon_valid(即将放置的行数, 即将放置的列数))
{
每行中皇后所处的列数[即将放置的行数] = 即将放置的列数;
if (即将放置的行数 == 7)
{
合法的摆放方式++;
print_map();
每行中皇后所处的列数[即将放置的行数] = 0;
return;
}
put_queen(即将放置的行数 + 1);
每行中皇后所处的列数[即将放置的行数] = 0;
}
}
}
void main()
{
put_queen(0);
printf("一共有%d种合法的摆放方式", 合法的摆放方式);
getchar();
}