C++——经典八后问题解析
这是我应聘现在这家公司的面试题,当时没做好,现在网上这个问题的代码已经很多了,问题也很透彻,排除因为棋盘的对称性带来的对称解,总共92种解法。
八后问题最常见的解法就是遍历法,一个八叉的遍历问题具体操作如下:
由于这个问题肯定是每行有一个后,把起始设为第一行
1.从第一列开始,放下一个后。
2.转移到第二行,从第一列,防下一个后,检验是否与前面冲突,若冲突,转到下一列;若不冲突,转移到下一行。以此类推。
遍历算法:
这个问题是一个典型的嵌套循环, 从第一行开始,执行8次循环,从第1列到第7列。——第一层循环
在第一层循环中,一旦成功放置旗子,则进入第二层循环,执行8次,从第1列到第7列,放置棋子前,要检验是否与已放置旗子冲突,若冲突,到下一列。——第二层循环
在第二层循环中,一旦成功放置旗子,则进入第三层循环,执行8次,从第1列到第7列,放置棋子前,要检验是否与已放置旗子冲突,若冲突,到下一列。——第三层循环
在第三层循环中,一旦成功放置旗子,则进入第四层循环,执行8次,从第1列到第7列,放置棋子前,要检验是否与已放置旗子冲突,若冲突,到下一列。——第四层循环
.(从第五行开始可能会出现全行都冲突的情况,这时候会跳出循环,进入到上一层循环的下一列,然后再回到这层循环)
.
.
当到第七行后,若有不冲突的位置,则直接打印。
冲突检测:
把冲突检测包装在方法里才能很好的兼容循环,那么如何才能最快的检验当前点(current_x,current_y),与现有的各个点(exist_x,exist_y)冲突呢,
首先一点就是,当我在循环中判断当前点是否冲突时,我只需判断当前行之前的各行即可,不会出现同行的情况。
所以判断的第一点就是是否同列:if(current_y==exist+y)
判断的第二点就是斜线方向了,斜线两个方向(current_x-current_y==exist_x-exisy_y) 和(current_x+current_y==exist_x+exisy_y)
这三个条件都不满足,才算不冲突,继续进入循环。
代码如下:
1 // 8-Queen_project.cpp : 定义控制台应用程序的入口点。 2 // 3 4 #include "stdafx.h" 5 #include<iostream> 6 using namespace std; 7 8 static int result_array[8] = { 0 }, total_count = 0; 9 void print() //打印 10 { 11 for (int i = 0; i < 8; i++) 12 { 13 for (int j = 0; j < result_array[i]; j++) 14 cout << " "; 15 cout << result_array[i] << endl; 16 } 17 cout << "--------\n"; 18 } 19 int confliction(int c_row, int c_column) 20 { 21 int this_row; 22 int this_column; 23 for (this_row = 0; this_row < c_row; this_row++) //只检验上面的行 24 { 25 this_column = result_array[this_row]; 26 if (c_column == this_column) 27 return 0; 28 if ((this_row + this_column) == (c_row + c_column)) 29 return 0; 30 if ((this_row - this_column) == (c_row - c_column)) 31 return 0; 32 } 33 return 1; 34 } 35 void loop(int row) // 参数就是行数 36 { 37 int column; 38 for (column = 0; column < 8; column++)//下面所有级的循环都结束,进入下一列 39 { 40 if (confliction(row, column)) 41 { 42 result_array[row] = column; 43 if (row == 7) //到最后一行打印 44 { 45 total_count++, print(); 46 result_array[row] = 0; 47 return; 48 } 49 loop(row + 1); //进入下一行循环 50 result_array[row] = 0; 51 } 52 } 53 } 54 int main(int argc, char*argv[]) 55 { 56 loop(0); 57 cout << "total=" << total_count << endl; 58 return 0; 59 }
结果如下,92种可以全部打印出来:
结果中数字代表列数。