回溯法:八皇后问题

什么是回溯法?

回溯来源于基本的枚举:

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个独立解,如何进行进一步优化是更深入的问题。本文旨在学习回溯的基本框架

 

posted on 2013-06-17 12:21  zjgtan  阅读(413)  评论(0编辑  收藏  举报

导航