zoukankan      html  css  js  c++  java
  • 回溯法解决八皇后问题

    1.“八皇后”问题

    八皇后问题是十九世纪著名数学家高斯于1850年提出的。问题是:在8*8的棋盘上摆放8个皇后,使其不能互相攻击,即任意的两个皇后不能处在同一行,同一列,或同一斜线上。可以把八皇后问题拓展为n皇后问题,即在n*n的棋盘上摆放n个皇后,使其任意两个皇后都不能处于同一行、同一列或同一斜线上。

    2.冲突条件判断

    如下图,方块内的值(i,j)表示第i行第j列。(1,1)位置如果放了皇后,那么(1,1)位置所在的行,列,斜线上都不能再放皇后。

    如何判断两个位置冲突呢?

    (1)判断两个位置是否再斜线上:根据斜率

    A(1,1)位置,B(2,0)位置和C(2,2)位置,A和B冲突:(0-1)/(2-1)==-1,A和C冲突:(2-1)/(2-1)==1。

    因此,对于任意两点A(x1,y1)和B(x2,y2),两点斜线冲突满足条件:abs((y2-y1)/(x2-x1))==1,

    该公式转换为:abs(y2-y1)== abs(x2-x1)

    (2)判断两个位置是否在同一列/同一行

    任意两点A(x1,y1)和B(x2,y2)在同一列满足条件:y1 == y2,在同一行满足条件:x1 == x2


    判断冲突代码如下:

    int valid(int row, int col)    //判断第row行第col列是否可以放置皇后
    {
        int i;
        for (i = 0; i < QUEEN; ++i)  //对已得到的解搜索,看是否冲突
        {   //判断列冲突与斜线上的冲突
            //表示第i行第col列放了皇后,(row - i) / (col - arr[i]) != 1 或 -1
            // arr[i] = k表示第i行第k列放了皇后
            if (a[i] == col || abs(i - row) == abs(a[i] - col))
                return 0;
        }
        return 1;
    }

    3.进入正题--回溯法解决

    (1)初始化棋盘

    #define INITIAL -10000 //棋盘的初始值
    const int QUEEN = 8;
    int
    a[QUEEN];//表示解空间a[1]=2表示[1,2]位置有皇后 void init()//初始化 { int *p; for(p=a;p<a+QUEEN;++p) *p = INITIAL; }

    (2)非递归回溯

    void queen()      //N皇后程序
    {
        int n = 0;
        int i = 0, j = 0;//i表示行,j表示每行的列
        while (i < QUEEN)//满足继续搜索的条件
        {
            ///没有到叶子结点情况下就继续搜索
            while (j < QUEEN)        //对i行的每一列进行探测,看是否可以放置皇后
            {
                if(valid(i, j))      //该位置可以放置皇后
                {
                    a[i] = j;        //第i行放置皇后,位置位j列
                    j = 0;           //第i行放置皇后以后,需要继续探测下一行的皇后位置,
                    //所以此处将j清零,从下一行的第0列开始逐列探测
                    break;
                }
                else
                {
                    ++j;             //继续探测下一列
                }
            }
            ///搜索到了叶子结点但是无解,直接回溯到上一行
            if(a[i] == INITIAL)         //第i行没有找到可以放置皇后的位置
            {
                if (i == 0)             //回溯到第一行,仍然无法找到可以放置皇后的位置,
                    //则说明已经找到所有的解,程序终止
                    break;
                else                    //没有找到可以放置皇后的列,此时就应该回溯
                {
                    --i;
                    j = a[i] + 1;        //把上一行皇后的位置往后移一列
                    a[i] = INITIAL;      //把上一行皇后的位置清除,重新探测
                    continue;
                }
            }
            //找到解
            if (i == QUEEN - 1)          //最后一行找到了一个皇后位置,
                //说明找到一个结果,打印出来
            {
                printf("answer %d : 
    ", ++n);
                print();
                //不能在此处结束程序,因为我们要找的是N皇后问题的所有解,
                //此时应该清除该行的皇后,从当前放置皇后列数的下一列继续探测。
                j = a[i] + 1;             //从最后一行放置皇后列数的下一列继续探测
                a[i] = INITIAL;           //清除最后一行的皇后位置
                continue;
            }
            ++i;              //继续探测下一行的皇后位置
        }
    }

    (3)结果打印

    void print()    //打印输出N皇后的一组解
    {
        int i, j;
        for (i = 0; i < QUEEN; ++i)
        {
            for (j = 0; j < QUEEN; ++j)
            {
                if (a[i] != j)      //a[i]为初始值
                    printf("%c ", '.');
                else                //a[i]表示在第i行的第a[i]列可以放置皇后
                    printf("%c ", '#');
            }
            printf("
    ");
        }
        for (i = 0; i < QUEEN; ++i)
            printf("%d ", a[i]);
        printf("
    ");
        printf("--------------------------------
    ");
    }
  • 相关阅读:
    HDOJ 1207 汉诺塔II
    [转]写代码的小女孩
    POJ Subway tree systems
    HDOJ 3555 Bomb (数位DP)
    POJ 1636 Prison rearrangement (DP)
    POJ 1015 Jury Compromise (DP)
    UVA 10003
    UVA 103 Stacking Boxes
    HDOJ 3530 Subsequence
    第三百六十二、三天 how can I 坚持
  • 原文地址:https://www.cnblogs.com/jainszhang/p/10701661.html
Copyright © 2011-2022 走看看