八皇后问题的扩展,任意数量皇后问题的较快速解法
今天看到一个简洁的例子来描述八皇后问题的文章,使用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种,这里就不一一列举了。