• C#数据结构与算法系列(十四):递归——八皇后问题(回溯算法)


    1.介绍

    八皇后问题,是一个古老而著名的问题,是回溯算法的经典案例,该问题是国际西洋棋棋手马克斯.贝瑟尔于1848年提出:在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,即

    任意两个皇后都不能处于同一行、同一列、同一斜线。问有多少种摆法(92)。

    2.思路分析

    第一个皇后先放第一行第一列

    第二个皇后放在第二行第一列,然后判断是否OK,如果不OK,继续放在第二列,第三列,依次把所有列都放完,找到一个合适

    继续放第三个皇后,还是第一列,第二列。。。知道第8个皇后也能放在一个不冲突的位置,算是找到一个正确解

    当得到一个正确解时,在栈中退到上一个栈时,就会开始回溯,即:将第一个皇后,放到第一列的所有正确解,全部得到

    然后回头继续放第一个皇后放第二列,后面继续循环执行执行1,2,4步骤

    说明:理论上应该创建一个二维数组来表示棋盘,但是实际上可以通过算法,用一个一维数组即可解决问题. arr[8] = {0 , 4, 7, 5, 2, 6, 1, 3} //对应arr 下标 表示第几行,即第几个皇后,arr[i] = val , val 表示第i+1个皇后,放在第i+1行的第val+1列

    3.图解

     4.代码实现

        public class EightQueens
        {
            //定义一个max表示共有多少个皇后
            static int _max = 8;
    
            //定义数组arr,保存皇后放置位置的结果,比如 arr={0,4,7,5,2,6,1,3}
            static int[] _arr = new int[_max];
    
            //初始化解法次数
            static int _count = 0;
    
            //初始化冲突次数
            static int _judgeCount = 0;
            public static void Test()
            {
                EightQueens.Check(0);
    
                Console.WriteLine($"一共有{_count}种解法");
    
                Console.WriteLine($"一共判断冲突的次数{_judgeCount}次");
            }
    
            /// <summary>
            ///编写一个方法,放置第n个皇后
            ///Check是每一次递归时,进入到Check中都有for(int i=0;i<_max;i++),因此会有回溯
            /// </summary>
            /// <param name="n"></param>
            private static void Check(int n)
            {
                if (n == _max) //当n=8,说明8个皇后已经方法,因为初始值从0开始
                {
                    Print();
    
                    return;
                }
    
                //依次放入皇后,并判断是否有冲突
                for (int i = 0; i < _max; i++)
                {
                    //先把当前这个皇后n,放到该行的第1列
                    _arr[n] = i;
    
                    //判断当放置第n个皇后到i列时,是否冲突
                    if (Judge(n))
                    {
                        //如果不冲突,接着放n+1个皇后,即开始递归
                        Check(n + 1);
                    }
    
                    //如果冲突,就继续执行arr[n]=i,即将第n个皇后,放置在本行的后移的一个位置
                }
            }
    
            /// <summary>
            /// 查看当我们放置第n个皇后,就去检查该皇后是否和前面已经判断的皇后冲突
            /// </summary>
            /// <param name="n">表示第n个皇后</param>
            /// <returns></returns>
            private static bool Judge(int n)
            {
                _judgeCount++;
    
                for (int i = 0; i < n; i++)
                {
                    //1._arr[i] == _arr[n] 表示判断第n个皇后,是否和前面的n-1个皇后在同一列
                    //2.Math.Abs(n - i) == Math.Abs(_arr[n] - _arr[i])表示判断第n个皇后是否和第i个皇后在同一个斜线
                    //取个例子:当 n=1的时候 也就是放置第2列 Math.Abs(1-0)==Math.Abs(1-0)=1
                    //3.判断是否在同一行,没有必要,n每次都在递增
                    if (_arr[i] == _arr[n] || Math.Abs(n - i) == Math.Abs(_arr[n] - _arr[i]))
                    {
                        return false;
                    }
                }
    
                return true;
            }
    
            /// <summary>
            /// 皇后的摆放位置输出
            /// </summary>
            private static void Print()
            {
                _count++;
    
                for (int i = 0; i < _arr.Length; i++)
                {
                    System.Console.Write(_arr[i] + " ");
                }
    
                System.Console.WriteLine();
            }
        }

    5.结果图

    0 4 7 5 2 6 1 3
    0 5 7 2 6 3 1 4
    0 6 3 5 7 1 4 2
    0 6 4 7 1 3 5 2
    1 3 5 7 2 0 6 4
    1 4 6 0 2 7 5 3
    1 4 6 3 0 7 5 2
    1 5 0 6 3 7 2 4
    1 5 7 2 0 3 6 4
    1 6 2 5 7 4 0 3
    1 6 4 7 0 3 5 2
    1 7 5 0 2 4 6 3
    2 0 6 4 7 1 3 5
    2 4 1 7 0 6 3 5
    2 4 1 7 5 3 6 0
    2 4 6 0 3 1 7 5
    2 4 7 3 0 6 1 5
    2 5 1 4 7 0 6 3
    2 5 1 6 0 3 7 4
    2 5 1 6 4 0 7 3
    2 5 3 0 7 4 6 1
    2 5 3 1 7 4 6 0
    2 5 7 0 3 6 4 1
    2 5 7 0 4 6 1 3
    2 5 7 1 3 0 6 4
    2 6 1 7 4 0 3 5
    2 6 1 7 5 3 0 4
    2 7 3 6 0 5 1 4
    3 0 4 7 1 6 2 5
    3 0 4 7 5 2 6 1
    3 1 4 7 5 0 2 6
    3 1 6 2 5 7 0 4
    3 1 6 2 5 7 4 0
    3 1 6 4 0 7 5 2
    3 1 7 4 6 0 2 5
    3 1 7 5 0 2 4 6
    3 5 0 4 1 7 2 6
    3 5 7 1 6 0 2 4
    3 5 7 2 0 6 4 1
    3 6 0 7 4 1 5 2
    3 6 2 7 1 4 0 5
    3 6 4 1 5 0 2 7
    3 6 4 2 0 5 7 1
    3 7 0 2 5 1 6 4
    3 7 0 4 6 1 5 2
    3 7 4 2 0 6 1 5
    4 0 3 5 7 1 6 2
    4 0 7 3 1 6 2 5
    4 0 7 5 2 6 1 3
    4 1 3 5 7 2 0 6
    4 1 3 6 2 7 5 0
    4 1 5 0 6 3 7 2
    4 1 7 0 3 6 2 5
    4 2 0 5 7 1 3 6
    4 2 0 6 1 7 5 3
    4 2 7 3 6 0 5 1
    4 6 0 2 7 5 3 1
    4 6 0 3 1 7 5 2
    4 6 1 3 7 0 2 5
    4 6 1 5 2 0 3 7
    4 6 1 5 2 0 7 3
    4 6 3 0 2 7 5 1
    4 7 3 0 2 5 1 6
    4 7 3 0 6 1 5 2
    5 0 4 1 7 2 6 3
    5 1 6 0 2 4 7 3
    5 1 6 0 3 7 4 2
    5 2 0 6 4 7 1 3
    5 2 0 7 3 1 6 4
    5 2 0 7 4 1 3 6
    5 2 4 6 0 3 1 7
    5 2 4 7 0 3 1 6
    5 2 6 1 3 7 0 4
    5 2 6 1 7 4 0 3
    5 2 6 3 0 7 1 4
    5 3 0 4 7 1 6 2
    5 3 1 7 4 6 0 2
    5 3 6 0 2 4 1 7
    5 3 6 0 7 1 4 2
    5 7 1 3 0 6 4 2
    6 0 2 7 5 3 1 4
    6 1 3 0 7 4 2 5
    6 1 5 2 0 3 7 4
    6 2 0 5 7 4 1 3
    6 2 7 1 4 0 5 3
    6 3 1 4 7 0 2 5
    6 3 1 7 5 0 2 4
    6 4 2 0 5 7 1 3
    7 1 3 0 6 4 2 5
    7 1 4 2 0 6 3 5
    7 2 0 5 1 4 6 3
    7 3 0 2 5 1 6 4
    一共有92种解法
    一共判断冲突的次数15720次
  • 相关阅读:
    springsecurity-用户注销
    springsecurity-自定义403页面
    springsecurity-用户授权 (注解使用)
    springsecurity-用户授权
    springsecurity-自定义登录页面和自定义认证
    springsecurity-查询数据库认证
    springsecurity-基本原理(过滤器链)
    springsecurity-web权限方案-用户认证(设置用户名和密码)
    u-boot移植(九)---代码修改---NAND
    u-boot移植(八)---代码修改---存储控制器--MMU
  • 原文地址:https://www.cnblogs.com/vic-tory/p/13191603.html
Copyright © 2020-2023  润新知