递归之八皇后问题

递归典例之八皇后问题

问题描述:

在8×8格的国际象棋上摆放8个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。

分析:先将棋盘的危险和安全数字化,1为危险,0为安全,皇后被放置前棋盘所有位置均为0。我们从第一列至第八列依次考虑,先考虑第一列,第一列我们有八种选择,但要注意,循环选择第一列元素时,要记得重置棋盘!选择一个位置我们用chose函数来表示。chose的作用是先判断此次选择的位置是不是最后一列,若不是,则将此次放置位置的同行同列及同对角线全置为1,并且将此次放置位置还原成0,将皇后与棋盘中未放置皇后的位置分离开来。然后列数加一,在该列安全的位置依次放置皇后,(即对该列元素为1的位置再次调用chose),同样要记住,此次调用结束到下次调用前,要将棋盘还原成未被本次循环调用前的模样。直到调用chose时,调用列即是最后一列,那么检测各列棋盘中放置皇后的行数(即数值为0的行数),输出行数的加一即可。
代码如下:
//声明: 棋盘中1为危险,0为安全
#include <stdio.h>
int solutionsum = 1;
//void print(int chessboard[][8],int m,int n);测试使用
void chose(int chessboard[][8],int row,int column);
void reset(int chessboard[][8]);
int main(void)
{
    int chessboard[8][8] = {0},i;
    for(i = 0; i < 8; i++)
    {
        chose(chessboard,i,0);  //按第一列依次选择元素
        reset(chessboard);      //将棋盘各元素重置为0
    }
    //chose(chessboard,7,0);测试使用
    //print(chessboard,8,8);测试使用
}
void print(int chessboard[][8],int m,int n)
{
    int i,j;
    for(i = 0; i < 8; i++)
    {
        for(j = 0; j < 8; j++)
        {
            printf("%d ",*(*(chessboard+i)+j));
        }
        printf("\n");
    }
}
void chose(int chessboard[][8],int row,int column)
{
    int i,j,k,l;
    int recordchessboard[8][8];     //记录棋盘状态
    if(column < 7)                  //若此时列非最后一列
    {
        for(i = 0; i < 8; i++)
        {
            for(j = 0; j < 8; j++)
            {
                if(i == row || j == column || (i - row) == (j - column) || (i - row) == (column - j))
                {
                    chessboard[i][j] = 1;
                }
            }
        }                           //函数本次选择元素的同列同行同对角线的元素全置1
        chessboard[row][column] = 0;//函数本次选择元素在上述置1过程中也被置1,为了与其他元素分辨,此处将其重置为0

        for(i = 0; i < 8; i++)
        {
            for(j = 0; j < 8; j++)
            {
                recordchessboard[i][j] = chessboard[i][j];
            }
        }                            //记录棋盘

        for(i = 0; i < 8; i++)
        {
                if(chessboard[i][column+1] == 0)
                {
                    chose(chessboard,i,column+1);//调用一次后棋盘变化,应将其还原至未被调用前的状态
                    for(k = 0; k < 8; k++)
                    {
                        for(l = 0; l < 8; l++)
                        {
                            chessboard[k][l] = recordchessboard[k][l];  //还原棋盘
                        }
                    }      
                }
        }
    }
    else
    {
        printf("[%2d]: ",solutionsum++);
        for(j = 0; j < 8; j++)
        {
            for(i = 0; i < 8; i++)
            {
                if(chessboard[i][j] == 0)
                {
                    printf("%d ",i+1);
                }
                
            }
        }
        printf("\n");
    } 
}
void reset(int chessboard[][8])
{
    int i,j;
    for(i = 0; i < 8; i++)
    {
        for(j = 0; j < 8; j++)
        {
            chessboard[i][j] = 0;
        }
    }
}

希望本篇文章对各位友友们有所帮助~


版权声明:本文为qq_51659538原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。