八皇后问题的扩展,任意数量皇后问题的较快速解法

    今天看到一个简洁的例子来描述八皇后问题的文章,使用stl算法next_permutation来对解全排列并分别验证,代码上确实简洁,不过感觉此法在运算中做了很多无谓的工作,效率上应该不佳。不过,在处理八个皇后的情况下,还是能够很快处理出所有解的,但是皇后数量多了的话,就是极大延长求解时长。

    八皇后问题,是一个古老而著名的问题,是回溯算法的典型例题。该问题是十九世纪著名的数学家高斯1850年提出:在8X8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。

    我这里做了一个算法,在一定程度上减少了重复计算,相信算法还有继续优化的空间:

  1 #include <tchar.h>
  2 #include <stdio.h>
  3 
  4 #define MAX_ITEM_COUNT      100
  5 
  6 #ifndef __cplusplus
  7 typedef int bool;
  8 #define true (1)
  9 #define false (0)
 10 #endif
 11 
 12 #define sTopLeft          "┌"
 13 #define sTopRight         "┐"
 14 #define sBottomLeft       "└"
 15 #define sBottomRight      "┘"
 16 #define sTop              "┬"
 17 #define sLeft             "├"
 18 #define sBottom           "┴"
 19 #define sRight            "┤"
 20 #define sVertical         "│"
 21 #define sHorizontal       "─"
 22 #define sCross            "┼"
 23 
 24 //输出函数
 25 void print_result(int map[], int item_count)
 26 {
 27     int i, j;
 28 
 29     printf(sTopLeft);
 30     for (i = 0; i < item_count - 1; i++)
 31     {
 32         printf("%s%s", sHorizontal, sTop);
 33     }
 34     printf("%s%s\n", sHorizontal, sTopRight);
 35 
 36     for (i = 0; i < item_count; i++)
 37     {
 38         printf(sVertical);
 39         for (j = 0; j < item_count; j++)
 40         {
 41             if (j == map[i])
 42             {
 43                 printf(" *%s", sVertical);
 44             }
 45             else
 46             {
 47                 printf("  %s", sVertical);
 48             }
 49         }
 50 
 51         printf("\n");
 52 
 53         if (i != item_count - 1)
 54         {
 55             printf(sLeft);
 56             for (j = 0; j < item_count - 1; j++)
 57             {
 58                 printf("%s%s", sHorizontal, sCross);
 59             }
 60             printf("%s%s\n", sHorizontal, sRight);
 61         }
 62     }
 63 
 64     printf(sBottomLeft);
 65     for (i = 0; i < item_count - 1; i++)
 66     {
 67         printf("%s%s", sHorizontal, sBottom);
 68     }
 69     printf("%s%s\n", sHorizontal, sBottomRight);
 70 }
 71 
 72 //检验是否是合法情形,只检验第index行即可
 73 bool check_cross(int map[], int item_count, int index)
 74 {
 75     int x = map[index];
 76     int y = index;
 77     int row = 0;
 78 
 79     for (; row < index; row += 1)
 80     {
 81         if (map[row] == x)
 82         {
 83             return false;
 84         }
 85         else
 86         {
 87             int xd = x - map[row];
 88             int yd = y - row;
 89 
 90             if (xd == yd || xd + yd == 0)
 91             {
 92                 return false;
 93             }
 94         }
 95     }
 96 
 97     return true;
 98 }
 99 
100 //更深的视图
101 int do_deep(int map[], int index)
102 {
103     map[++index] = 0;
104 
105     return index;
106 }
107 
108 //下一个视图
109 int do_next(int map[], int item_count, int index)
110 {
111     map[index] += 1;
112 
113     if (map[index] < item_count)
114     {
115         return index;
116     }
117 
118     index -= 1;
119 
120     if (index < 0)
121     {
122         return -1;
123     }
124 
125     return do_next(map, item_count, index);
126 }
127 
128 //求解函数,参数为皇后数量,和是否得到一个解就退出
129 bool Resolve(int item_count, bool get_one_exit)
130 {
131     int map[MAX_ITEM_COUNT] = {0};
132     int index = 0;
133 
134     if (item_count < 1 || item_count > MAX_ITEM_COUNT)
135     {
136         return false;
137     }
138 
139     while (true)
140     {
141         bool cross_ok = check_cross(map, item_count, index);
142 
143         if (cross_ok && index == item_count - 1)
144         {
145             print_result(map, item_count);
146 
147             if (get_one_exit)
148             {
149                 break;
150             }
151         }
152 
153         if (cross_ok && index < item_count - 1)
154         {
155             index = do_deep(map, index);
156         }
157         else
158         {
159             index = do_next(map, item_count, index);
160         }
161 
162         if (index == -1)
163         {
164             break;
165         }
166     }
167 
168     return true;
169 }
170 
171 int _tmain()
172 {
173     //
174     return !Resolve(8, false);
175 }

 

    28个皇后情况下的一个解:

    8皇后问题的所有解有92种,这里就不一一列举了。

posted on 2013-03-29 15:52  Shilyx  阅读(1891)  评论(0编辑  收藏  举报

导航