八皇后问题,是一个古老而著名的问题,是回溯算法的典型例题。该问题是十九世纪著名的数学家高斯1850年提出:在8X8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
typedef enum
{
false = 0,
true = 1
} bool_t;
// col mask
// +-----------------+
// | 1 2 3 4 5 6 7 8 |
// | 1 2 3 4 5 6 7 8 |
// | 1 2 3 4 5 6 7 8 |
// | 1 2 3 4 5 6 7 8 |
// | 1 2 3 4 5 6 7 8 |
// | 1 2 3 4 5 6 7 8 |
// | 1 2 3 4 5 6 7 8 |
// | 1 2 3 4 5 6 7 8 |
// +-----------------+
enum
{
COL_MASK_NONE = 0x000, // 0 0000 0000
COL_MASK_1 = 0x001, // 0 0000 0001
COL_MASK_2 = 0x002, // 0 0000 0010
COL_MASK_3 = 0x004, // 0 0000 0100
COL_MASK_4 = 0x008, // 0 0000 1000
COL_MASK_5 = 0x010, // 0 0001 0000
COL_MASK_6 = 0x020, // 0 0010 0000
COL_MASK_7 = 0x040, // 0 0100 0000
COL_MASK_8 = 0x080, // 0 1000 0000
COL_MASK_ALL = 0x0FF // 0 1111 1111
};
#define LONG_ROW_COUNT (8)
typedef struct
{
int base_col; // start col 0~7:valid, -1:invalid
int curr_col; // current col 0~7:valid, -1:invalid
unsigned int col_mask;
} col_index_t;
typedef struct{
int long_row; // long_row 0~7:valid, -1:init, 8:finish
col_index_t col_index[LONG_ROW_COUNT]; // col_index[row]
} queue8_t;
void init_queue8(queue8_t * queue8);
bool_t queue8_not_finish(queue8_t *queue8);
void goto_next_row(queue8_t *queue8);
void rollback_row(queue8_t *queue8);
int calc_rand_col(void);
int calc_next_col(int col);
void calc_col_mask_row(queue8_t *queue8, int long_row);
bool_t goto_next_col(queue8_t *queue8);
void print_queue8(queue8_t *queue8);
int main(int argc, const char * argv[])
{
queue8_t queue8;
srand((unsigned int)time((time_t *)NULL));
init_queue8(&queue8);
goto_next_row(&queue8);
while(queue8_not_finish(&queue8))
{
if(goto_next_col(&queue8))
{
goto_next_row(&queue8);
}
else
{
rollback_row(&queue8);
}
}
print_queue8(&queue8);
return 0;
}
void init_queue8(queue8_t * queue8)
{
do
{
if(queue8 == NULL)
break;
memset(queue8, 0, sizeof(queue8_t));
queue8->long_row = -1; // init invalid long_row
} while(false);
}
bool_t queue8_not_finish(queue8_t *queue8)
{
bool_t not_finish = false;
do
{
if(queue8 == NULL)
break;
if(queue8->long_row < LONG_ROW_COUNT)
{
not_finish = true;
}
} while(false);
return not_finish;
}
void goto_next_row(queue8_t *queue8)
{
do
{
if(queue8 == NULL)
break;
queue8->long_row++;
if(queue8->long_row >= LONG_ROW_COUNT)
break;
/* init col index */
queue8->col_index[queue8->long_row].base_col = calc_rand_col(); // random col
queue8->col_index[queue8->long_row].curr_col = -1; // invalid col
/* init col mask */
calc_col_mask_row(queue8, queue8->long_row);
} while(false);
}
void rollback_row(queue8_t *queue8)
{
do
{
if(queue8 == NULL)
break;
queue8->long_row--;
/* init col mask */
calc_col_mask_row(queue8, queue8->long_row);
} while(false);
}
int calc_rand_col(void)
{
int col;
col = rand() % 8; // col 0~7
return col;
}
int calc_next_col(int col)
{
return (col + 1) % 8; // col 01234567 => 12345670
}
void calc_col_mask_row(queue8_t *queue8, int long_row)
{
int row;
unsigned int mask = COL_MASK_NONE;
for(row = 0; row < long_row; row++)
{
mask |= queue8->col_index[row].col_mask;
mask |= queue8->col_index[row].col_mask >> (long_row - row);
mask |= queue8->col_index[row].col_mask << (long_row - row);
}
queue8->col_index[long_row].col_mask = ~mask; // store cols that can place
}
bool_t goto_next_col(queue8_t *queue8)
{
bool_t success = false;
int base_col;
int curr_col;
int next_col;
bool_t found = false;
do
{
if(queue8 == NULL)
break;
base_col = queue8->col_index[queue8->long_row].base_col;
curr_col = queue8->col_index[queue8->long_row].curr_col;
found = false;
if(curr_col == -1)
{
// find first
next_col = base_col;
// base_col is valid
if(queue8->col_index[queue8->long_row].col_mask & (1 << base_col))
{
found = true;
next_col = base_col;
}
else
{
next_col = calc_next_col(base_col);
}
}
else
{
next_col = calc_next_col(curr_col);
}
if(!found)
{
// find next
while(next_col != base_col)
{
// next_col is valid
if(queue8->col_index[queue8->long_row].col_mask & (1 << next_col))
{
found = true;
break;
}
// find next
next_col = calc_next_col(next_col);
}
}
if(!found)
break;
// set next_col
queue8->col_index[queue8->long_row].curr_col = next_col;
queue8->col_index[queue8->long_row].col_mask = (1 << next_col); // store selected col
success = true;
} while(false);
return success;
}
void print_queue8(queue8_t *queue8)
{
int long_row;
int row;
int col;
int digit;
int cell[64] = { 0 };
do
{
if(queue8 == NULL)
break;
for(long_row = 0; long_row < queue8->long_row; long_row++)
{
row = long_row % 8;
col = queue8->col_index[long_row].curr_col;
digit = long_row / 8 + 1;
cell[row * 8 + col] = digit;
}
printf("Queen %d\n", queue8->long_row);
printf("+-----------------+\n");
for(row = 0; row < 8; row++)
{
printf("| ");
for(col = 0; col < 8; col++)
{
if (cell[row * 8 + col])
printf("Q ");
else
printf(". ");
}
printf("|\n");
}
printf("+-----------------+\n");
} while(false);
}
输出的随机局面:
Queen 8
+-----------------+
| . . . Q . . . . |
| Q . . . . . . . |
| . . . . Q . . . |
| . . . . . . . Q |
| . Q . . . . . . |
| . . . . . . Q . |
| . . Q . . . . . |
| . . . . . Q . . |
+-----------------+