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种可以全部打印出来:

结果中数字代表列数。

 

posted @ 2016-09-26 01:05  铁杆  阅读(605)  评论(0编辑  收藏  举报