zoukankan      html  css  js  c++  java
  • 八皇后问题-dfs

    一、题意解析

      国际象棋中的皇后,可以横向、纵向、斜向移动。如何在一个8X8的棋盘上放置8个皇后,使得任意两个皇后都不在同一条横线、竖线、斜线方向上?八皇后问题是一个古老的问题,于1848年由一位国际象棋棋手提出:在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,如何求解?以高斯为代表的许多数学家先后研究过这个问题。后来,当计算机问世,通过计算机程序的运算可以轻松解出这个问题。

    二、如何解决八皇后问题?

      所谓递归回溯,本质上是一种枚举法。这种方法从棋盘的第一行开始尝试摆放第一个皇后,摆放成功后,递归一层,再遵循规则在棋盘第二行来摆放第二个皇后。如果当前位置无法摆放,则向右移动一格再次尝试,如果摆放成功,则继续递归一层,摆放第三个皇后......

      如果某一层看遍了所有格子,都无法成功摆放,则回溯到上一个皇后,让上一个皇后右移一格,再进行递归。如果八个皇后都摆放完毕且符合规则,那么就得到了其中一种正确的解法。说起来有些抽象,我们来看一看递归回溯的详细过程。

      1.第一层递归,尝试在第一行摆放第一个皇后

      2.第二层递归,尝试在第二行摆放第二个皇后(前两格被第一个皇后封锁,只能落在第三格):

      3.第三层递归,尝试在第三行摆放第三个皇后(前四格被第一第二个皇后封锁,只能落在第五格):

      4.第四层递归,尝试在第四行摆放第四个皇后(第一格被第二个皇后封锁,只能落在第二格):

      5.第五层递归,尝试在第五行摆放第五个皇后(前三格被前面的皇后封锁,只能落在第四格):

      6.由于所有格子都“绿了”,第六行已经没办法摆放皇后,于是进行回溯,重新摆放第五个皇后第八格。:

      7.第六行仍然没有办法摆放皇后,第五行也已经尝试遍了,于是回溯到第四行,重新摆放第四个皇后第七格。:

      8.继续摆放第五个皇后,以此类推......

    代码:打印所有的摆放方法以及方法总数

    #include<stdio.h>
    #include<algorithm>
    #include<string.h>
    #include<string>
    #include<sstream>
    #include<iostream>
    using namespace std;
    
    int num=0;
    
    void output(bool arr[8][8])
    {
        num++;
        printf("
    ");
        for(int i=0;i<8;i++)
        {
            for(int j=0;j<8;j++)
                printf("%d ",arr[i][j]);
            printf("
    ");
        }
    }
    
    bool check(bool arr[8][8],int row,int column)///检查落子是否合法,参数分别是行,列
    {
        if(row==0)  ///第一行落子肯定合法
            return true;
    
        ///一行只摆一个就换行,所以不用判断行是否合法
    
        int i,j;///判断同一列上有没有棋子
        for(i=0;i<row;i++)
        {
            if(arr[i][column])
                return false;
        }
        i=row-1;
        j=column-1;///判断左上斜线是否有棋子
        while(i>=0&&j>=0)
        {
            if( arr[i][j] )
            {
                return false;
            }
            i--;
            j--;
        }
        i=row-1;
        j=column+1;///判断右上斜线是否有棋子
        while(i>=0&&j<8)
        {
            if( arr[i][j] )
            {
                return false;
            }
            i--;
            j++;
        }
        return true;
    }
    
    void slove(bool arr[8][8],int row)///回溯法,核心代码
    {///从第一行第一列开始摆放,如果合法就继续摆,深度搜索所有答案
        for(int column=0;column<8;column++)
        {
            arr[row][column]=true;///摆下去先,再判断是否落子合法
            if( check(arr,row,column) )
            {
                if( row+1==8 )  ///摆到第八行,并且落子合法,则棋盘正确摆放了
                    output(arr);
                else
                    slove(arr,row+1);///如果该落子合法,又没有到第八行,则继续下一行开摆
            }
            arr[row][column]=false;///不摆这一颗子,摆下一颗子进行深度搜索
        }
    }
    int main()
    {
        bool chess[8][8];
        memset(chess,false,sizeof(chess));
        slove(chess,0);
        printf("num=%d
    ",num);
        return 0;
    }
  • 相关阅读:
    Qt串口的使用记录
    CImage灰度化
    (记录)MSYS2+MINGW32编译ffmpeg过程
    Blas 基本函数功能
    blas中dgemm_的用法
    选择、插入、冒泡排序
    简单的页面
    中国大学排名
    爬bing 主页
    读书报告
  • 原文地址:https://www.cnblogs.com/shoulinniao/p/10260317.html
Copyright © 2011-2022 走看看