您的位置:首页 > 其它

软件设计师算法之回溯法--8皇后问题

2017-09-16 13:34 423 查看
    8皇后问题,我想IT人士应该基本都听过了。特别是会下国际象棋的。规则很简单,每一个皇后会攻击每一条线的其它皇后,因此要确保每一条线上(包括直线和对角斜线)只能存在一个皇后。8皇后问题我一直没有编写过代码去实现。今天正好补上。

    如下是实现代码:

#define MAX_ROW    8
#define MAX_COLUMN 8

unsigned char g_QueenArray[MAX_ROW][MAX_COLUMN] = {0};
unsigned int g_QueenSolveCount = 0;

void QueenSolve(int row);

void QueenTest()
{
QueenSolve(0);
printf("\r\nTotal count of queen solve = %d\r\n",g_QueenSolveCount);
}

BOOL QueenCheck(int row,int column)
{
/* 每一行只能有一个皇后,前面解法已保证,不用check*/
/* 每一列只能有一个皇后 */
for(int i=0;i<row;i++)
{
if(g_QueenArray[i][column])
{
return FALSE;
}
}
/* 左上角对角线只能有一个皇后 */
int i = row-1;
int j = column-1;
do
{
//如果超出边界了,那么直接break
if(i<0 || j<0)
{
break;
}
if(g_QueenArray[i][j])
{
return FALSE;
}
i--;
j--;
} while (1);

/* 右上角对角线只能有一个皇后 */
i = row-1;
j = column+1;
do
{
//如果超出边界了,那么直接break
if(i<0 || j>=MAX_COLUMN)
{
break;
}
if(g_QueenArray[i][j])
{
return FALSE;
}
i--;
j++;
} while (1);

return TRUE;
}

void PrintQueen()
{
printf("One of Queen solve result:\r\n");
for(int i=0;i<MAX_ROW;i++)
{
for(int j=0;j<MAX_COLUMN;j++)
{
printf("%2d",g_QueenArray[i][j]);
}
printf("\r\n");
}
}

void QueenSolve(int row)
{
for(int j=0;j<MAX_COLUMN;j++)
{
g_QueenArray[row][j] = 1;
if(QueenCheck(row,j))
{
if(MAX_ROW-1 == row)
{
PrintQueen();//找到一组解答,之后会继续回溯
g_QueenSolveCount++;
}
else
{
QueenSolve(row+1);//前往下一行
}
}
g_QueenArray[row][j] = 0;//回溯,在下一列放置皇后,尝试可能性
}
}


     测试运行,输出92种结果。见如下图:

     


    

      但是到这里并没有结束。其实上面的回溯法有关问题,就是效率不高。首先是大量的递归,其次是搜索的空间太大,导致运行的时间会很长。8皇后问题运行的时间一般不会超过1秒(debug版本在我电脑上运行时间为452ms)。但是如果把行和列扩展为12,

          #define MAX_ROW         12   

          #define MAX_COLUMN 12

    计算运行时间:

void QueenTest()
{
DWORD starTime =GetTickCount();

QueenSolve(0);
printf("\r\nTotal count of queen solve = %d\r\n",g_QueenSolveCount);

DWORD endTime=GetTickCount();
printf("Running Total time = %d\r\n",endTime-starTime);
}
     12*12皇后问题,debug版本在我的电脑上运行时间为104秒:



         可以看到,运行的时间是巨大的。如果是16*16皇后呢,32*32呢,64*64呢,搜索空间会越来越大导致运行时间不可接受。

         我们有2种办法可以优化,一是把递归修改为迭代实现,二是通过枝减尽快把一些不可能解排除。具体的实现就先遗留在这里。等有空再编写代码实现吧。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息