回溯法:八皇后问题

什么是回溯法?

回溯来源于基本的枚举:

void print(序列A, 集合S)

{

    if (S为空) 输出序列A

    else 按照“从小到大的顺序”依次考虑S中的每个元素

    {

        print(A的新序列, S-{v}); //递归

    }           

}

其中,测试元素通过一个for循环加入,递归通过cur下标指示当前位置。很明显,这是一个对解答树的先序遍历过程,叶节点就是问题的解。

但是,当问题规模扩大时枚举量指数级的扩大。问题在于枚举将解的判断置于叶节点,而忽视了搜索路径中的判断。因此回溯就应运而生,也就是在测试节点加入时就测试合理性,(合理) ? 递归:剪枝。对于不同的问题,递归框架明确,最重要的是确定判决条件。

八皇后问题:皇后不同行、同列、同对角线。对角线相当于y=x+c和y=-x+c这两组平行线。程序:

#include <stdio.h>



int maze[8]; //保存各行选择的列

int cnt = 0; //解的个数



void dfs(int row)

{

    if (row == 8)

    { //递归结束条件

        cnt++;

        for (int i = 0; i < 8; i++)

            printf("%d ", maze[i]);

        printf("\n");

    }

    else

    {

        for (int i = 0; i < 8; i++)

        {//遍历cur行上的所有可能解

            int ok = 1;

            for (int j = 0; j < row; j++)

            {//判断与先前的节点时候冲突

                if (maze[j] == i || (j - maze[j]) == (row - i) || (j + maze[j]) == (row + i))

                {//同列 同对角线

                    ok = 0;

                    break;

                }

            }



            if (ok)

            {//不冲突则加入,继续执行递归

                maze[row] = i;

                dfs(row + 1);

            }//否则剪枝,测试下一个可能解

        }

    }

}



int main()

{

    dfs(0);

    printf("cnt = %d\n", cnt);

    return 0;    

}

最后共有92个解。但是事实上只有12个独立解,如何进行进一步优化是更深入的问题。本文旨在学习回溯的基本框架

 

你可能感兴趣的:(八皇后)