八皇后问题的分析与解法

问题描述:

八皇后问题的分析与解法_第1张图片

在8*8的国际象棋棋盘上,要求在每一行(或者每一列)放置一个皇后,且能做到在水平方向、竖直方向和斜方向都没有冲突。请列出所有解法。


根据上述描述,我们可以得到如果两个皇后Q1(x, y)和Q2(row, col)不符合要求,则以下四个条件之一必符合。

1 ) x == row

2 ) y == col

3 ) x + y == row + col (斜向正方向)

4 ) x - y == row - col(斜向反方向)


归纳出了程序的判断条件,下面用主流的回溯法来解决N皇后问题,这里是8皇后问题。回溯法也就是带有剪枝的深度优先遍历。

用回溯的方法解决8皇后问题的步骤为:
1)从第一列开始,为皇后找到安全的一行,然后开始下一列
2)如果在第n列出现死胡同,则完全放弃后面所有列的搜索,直接后退到上一列,进行回溯
3)如果在第8列上找到了安全位置,则棋局成功。

8个皇后都找到了安全位置代表棋局的成功,用一个长度为8的整数数组colume代表成功摆放的8个皇后,数组索引代表棋盘的col向量,而数组的值为棋盘的row向量,所以(row,col)的皇后可以表示为(colume[col],col)

#include 
#include 

#define QUEEN_NUM 8
int ResultCounter = 0;

void printResult(int colume[]);
bool check(int colume[], int col);
void QueenSolution(int colume[], int col);

int main(void){
    //数组colume中存放的是行值
    //即假设col[0]==3,表明第1列中皇后在第4行上
    int colume[QUEEN_NUM] = {0};
    QueenSolution(colume, 0);
    std::cout << "Solution Total Count: " << ResultCounter << std::endl;
}


//输出数组中的一组结果
void printResult(int colume[]){
    for(int i = 0; i < QUEEN_NUM; i++)
        std::cout << "(" << colume[i] << ", " << i << ") ";
    std::cout << std::endl;
    ResultCounter++;
}

//检查当前列col,在现有情况下,能否放置皇后
//如果是以下四种情况,就返回false
//1)x=row(在纵向不能有两个皇后)
//2)  y=col(横向)
//3)col + row = y+x;(斜向正方向)
//4)  col - row = y-x;(斜向反方向)
bool check(int colume[], int col){
    //因为提供的是列信息,我们就逐列进行检查
    for(int i = 0; i < col; i++)
    {
        if(colume[i] == colume[col] ||
           std::abs(colume[i] - colume[col]) == col - i )
            return false;
    }
    return true;
}

//尝试第col列上的所有解
//即在第col列的所有行上依次检验
//调用此函数时,表明从第0列到第col-1列都已经安置好了皇后
void QueenSolution(int colume[], int col){
    if(col == QUEEN_NUM)
    {
        printResult(colume);
        return;
    }

    //新的一列中,皇后有可能在任意一行
    for(int i = 0; i < QUEEN_NUM; i++)
    {
        colume[col] = i;  //将这个皇后放在第i行,进行检查
        if( check(colume, col) )
            QueenSolution(colume, col+1);
    }
}

PS.结果为92个。


你可能感兴趣的:(算法,刷题系列)