C学习笔记之---八皇后算法

来源:互联网 发布:mamercache缓存php 编辑:程序博客网 时间:2024/05/22 06:26

转载出处:http://www.cnblogs.com/ZiQi-pro/archive/2011/12/21/2296093.html

在下面所示的棋盘中,皇后可以攻击位于箭头所覆盖的位置的所有棋子,那么现在有八个皇后,如何放置可以让他们之间不会相互攻击呢?

 

image

本文采用回溯法,先附上维基百科上对回溯法的解释:

“ 回溯法(英语:backtracking)是穷尽搜索算法(英语:Brute-force search)中的一种。

回溯法采用试错的思想,它尝试分步的去解决一个问题。在分步解决问题的过程中,当它通过尝试发现现有的分步答案不能得到有效的正确的解答的时候,它将取消上一步甚至是上几步的计算,再通过其它的可能的分步解答再次尝试寻找问题的答案。回溯法通常用最简单的递归方法来实现,在反复重复上述的步骤后可能出现两种情况:

1、找到一个可能存在的正确的答案 
2、在尝试了所有可能的分步方法后宣告该问题没有答案

在最坏的情况下,回溯法会导致一次复杂度为指数时间的计算。”

将皇后放置某一行的第一列,检查是否与棋盘中的其他皇后相互攻击,如果存在,那么将皇后放置这一行的第二列再进行检查。如果每列都存在相互攻击,返回到上一行放置皇后的位置,查找上一行中下一个可以放置皇后的位置,如果存在再检查这一行。以下为代码:

打印棋盘:

#include
 
#define TRUE 1
#define FALSE 0
 
int board[8][8];   /*棋盘*/
 
/* print_board
** 打印解决方案
*/
void
print_board()
{
    int row,
        column;
    static int n_solutions;
 
    n_solutions += 1;
    printf("答案 %d:\n",n_solutions);
 
    for(row = 0;row < 8;++row)
    {
        for (column = 0;column < 8; ++column)
        {
            board[row][column]?printf("Q"):printf("+");
        }
        putchar('\n');
    }
    putchar('\n');
}

检查冲突:

/* conflicts
** 用于检查某一行某一列是否与其他行列相互攻击
** 斜下方与正下方不需要检查,因为当前下方位置没有皇后
*/
int
conflicts(int row,int column)
{
    int i;
    for (i = 1;i<8;++i)
    {
        /*上*/
        if (row - i >= 0 && board[row - i][column])return TRUE;
 
        /*左*/
        if (column -i >= 0 && board[row][column - i])return TRUE;
 
        /*右*/
        if (column + i < 8 && board[row][column + i])return TRUE;
 
        /*斜左上方*/
        if(column - i >= 0 && row - i >= 0 && board[row - i][column - i])return TRUE;
 
        /*斜右上方*/
        if(column + i < 8 && row - i >= 0 && board[row - i][column + i])return TRUE;
    }
    /*不存在相互攻击,返回false*/
    return FALSE;
}

放置皇后:

/* place_queen
** 放置皇后
** 第一行不需要检查,因为只有一个皇后。皇后放置的位置设置为true。
** 如果某M行的所有列放置皇后都存在互相攻击,那么需要返回到M-1行中放置皇后的位置,
** 将M-1行的皇后位置设置为false,寻找这行的下一个可以放置皇后的位置,如果存在再检查第M行可以放置皇后的位置。
** 如果不存在,则返回到第M-2行。
** 如果8个皇后成功放置完毕,则打印棋盘.
*/
void
place_queen(int row)
{
    int column;
    for (column = 0;column < 8; ++column)
    {
        board[row][column] = TRUE;
        if (row == 0 || !conflicts(row,column))
        {  
            if (row < 7)
            {
                place_queen(row + 1);
            }
            else
            {
                print_board();
            }
        }
        board[row][column] = FALSE;
    }
}
 
int
main()
{
    place_queen(0);
    return 0;
}

place_queen函数可能不太好理解,看下图会好些。

皇后第一次放置,最后一行的皇后与第一行的皇后存在相互攻击。

image

返回到倒数第二行,将倒数第二行的皇后放置在该行的可以放置皇后的第二个位置。

image

放置最后一行的皇后,依然存在相互攻击。

image

这时需要返回到倒数第三行,因为倒数第二行已经可以放置皇后的位置已尝试过。以此类推,最后得到可以放置八皇后的答案。

希望此文对你有帮助。


0 0