今天看到一个简洁的例子来描述八皇后问题的文章,使用stl算法next_permutation来对解全排列并分别验证,代码上确实简洁,不过感觉此法在运算中做了很多无谓的工作,效率上应该不佳。不过,在处理八个皇后的情况下,还是能够很快处理出所有解的,但是皇后数量多了的话,就是极大延长求解时长。
八皇后问题,是一个古老而著名的问题,是回溯算法的典型例题。该问题是十九世纪著名的数学家高斯1850年提出:在8X8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。
我这里做了一个算法,在一定程度上减少了重复计算,相信算法还有继续优化的空间:
#include <tchar.h>
#include <stdio.h>
#define MAX_ITEM_COUNT 100
#ifndef __cplusplus
typedef int bool;
#define true (1)
#define false (0)
#endif
#define sTopLeft "┌"
#define sTopRight "┐"
#define sBottomLeft "└"
#define sBottomRight "┘"
#define sTop "┬"
#define sLeft "├"
#define sBottom "┴"
#define sRight "┤"
#define sVertical "│"
#define sHorizontal "─"
#define sCross "┼"
//输出函数
void print_result(int map[], int item_count)
{
int i, j;
printf(sTopLeft);
for (i = 0; i < item_count - 1; i++)
{
printf("%s%s", sHorizontal, sTop);
}
printf("%s%s\n", sHorizontal, sTopRight);
for (i = 0; i < item_count; i++)
{
printf(sVertical);
for (j = 0; j < item_count; j++)
{
if (j == map[i])
{
printf(" *%s", sVertical);
}
else
{
printf(" %s", sVertical);
}
}
printf("\n");
if (i != item_count - 1)
{
printf(sLeft);
for (j = 0; j < item_count - 1; j++)
{
printf("%s%s", sHorizontal, sCross);
}
printf("%s%s\n", sHorizontal, sRight);
}
}
printf(sBottomLeft);
for (i = 0; i < item_count - 1; i++)
{
printf("%s%s", sHorizontal, sBottom);
}
printf("%s%s\n", sHorizontal, sBottomRight);
}
//检验是否是合法情形,只检验第index行即可
bool check_cross(int map[], int item_count, int index)
{
int x = map[index];
int y = index;
int row = 0;
for (; row < index; row += 1)
{
if (map[row] == x)
{
return false;
}
else
{
int xd = x - map[row];
int yd = y - row;
if (xd == yd || xd + yd == 0)
{
return false;
}
}
}
return true;
}
//更深的视图
int do_deep(int map[], int index)
{
map[++index] = 0;
return index;
}
//下一个视图
int do_next(int map[], int item_count, int index)
{
map[index] += 1;
if (map[index] < item_count)
{
return index;
}
index -= 1;
if (index < 0)
{
return -1;
}
return do_next(map, item_count, index);
}
//求解函数,参数为皇后数量,和是否得到一个解就退出
bool Resolve(int item_count, bool get_one_exit)
{
int map[MAX_ITEM_COUNT] = {0};
int index = 0;
if (item_count < 1 || item_count > MAX_ITEM_COUNT)
{
return false;
}
while (true)
{
bool cross_ok = check_cross(map, item_count, index);
if (cross_ok && index == item_count - 1)
{
print_result(map, item_count);
if (get_one_exit)
{
break;
}
}
if (cross_ok && index < item_count - 1)
{
index = do_deep(map, index);
}
else
{
index = do_next(map, item_count, index);
}
if (index == -1)
{
break;
}
}
return true;
}
int _tmain()
{
//
return !Resolve(8, true);
}
附:28个皇后情况下的一个解:
8皇后问题的所有解有92种,这里就不一一列举了。