递归求解八皇后问题

本文详细介绍了八皇后问题的回溯算法求解过程,包括算法实现的细节和输出的随机局面展示。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

八皇后问题,是一个古老而著名的问题,是回溯算法的典型例题。该问题是十九世纪著名的数学家高斯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 . . |
+-----------------+
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值