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("--------------------------------
    ");
    }
  • 相关阅读:
    Elasticsearch Network Settings
    Spring Application Event Example
    hibernate persist update 方法没有正常工作(不保存数据,不更新数据)
    快速自检电脑是否被黑客入侵过(Linux版)
    快速自检电脑是否被黑客入侵过(Windows版)
    WEB中的敏感文件泄漏
    Nginx日志分析
    关系型数据库设计小结
    软件开发的一些"心法"
    关于DNS,你应该知道这些
  • 原文地址:https://www.cnblogs.com/jainszhang/p/10701661.html
Copyright © 2011-2022 走看看