C#八皇后算法:回溯法 vs 列优先法 vs 行优先法 vs 对角线优先法

这篇具有很好参考价值的文章主要介绍了C#八皇后算法:回溯法 vs 列优先法 vs 行优先法 vs 对角线优先法。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

1.八皇后算法(Eight Queens Puzzle)

2.常见的八皇后算法解决方案

(1)列优先法(Column-First Method):

(2)行优先法(Row-First Method):

(3)对角线优先法(Diagonal-First Method):

(4)回溯法(Backtracking):


1.八皇后算法(Eight Queens Puzzle)

       皇后问题是一个古老而著名的问题,它实质上就是使棋盘上的8个皇后不能在同一行、同一列或同一条斜线上,共有92种方案。

2.常见的八皇后算法解决方案

        八皇后算法的解决方案有多种,以下是一些常见的解决方案:

(1)列优先法(Column-First Method):

        八皇后问题是一个经典的回溯算法问题,可以使用列优先法(或称为逐列解决法)来解决。 首先选择一个空的棋盘,然后从第一行开始,尝试将皇后放置在每一列。如果当前列没有被攻击,那么就将皇后放置在该列。否则,尝试下一列。当找到一个有效的列时,将皇后放置在该列的最下方。重复这个过程,直到所有的皇后都被放置在棋盘上。

// 使用列优先法解决八皇后问题
// 列优先算法也叫逐列解决法

namespace _144_4
{
    class Program
    {
        private const int Size = 8;
        private readonly int[] queens = new int[Size];               // 存储每行皇后的列位置
        private readonly bool[] columns = new bool[Size];            // 列是否已被占用
        private readonly bool[] diagonals1 = new bool[2 * Size - 1]; // 主对角线是否已被占用
        private readonly bool[] diagonals2 = new bool[2 * Size - 1]; // 副对角线是否已被占用

        public void Solve()
        {
            PlaceQueen(0);
        }

        int solnum = 0;
        private void PlaceQueen(int row)
        {
            if (row == Size)
            {
                solnum += 1;
                PrintQueens(solnum);  // 所有皇后都已放置,打印结果
                return;
            }

            for (int col = 0; col < Size; col++)
            {
                if (IsSafe(row, col))
                {
                    queens[row] = col;
                    columns[col] = true;
                    diagonals1[row - col + Size - 1] = true;
                    diagonals2[row + col] = true;

                    PlaceQueen(row + 1);

                    // 回溯
                    diagonals2[row + col] = false;
                    diagonals1[row - col + Size - 1] = false;
                    columns[col] = false;
                }
            }
        }

        private bool IsSafe(int row, int col)
        {
            return !columns[col] && !diagonals1[row - col + Size - 1] && !diagonals2[row + col];
        }

        private void PrintQueens(int solnum)
        {
            Console.WriteLine("Solution{0}: ", solnum);
            for (int i = 0; i < Size; i++)
            {
                for (int j = 0; j < Size; j++)
                {
                    if (queens[i] == j)
                    {
                        Console.Write("Q ");
                    }
                    else
                    {
                        Console.Write("* ");
                    }
                }
                Console.WriteLine();
            }
            Console.WriteLine();
        }

        public static void Main(string[] args)
        {
            ArgumentNullException.ThrowIfNull(args);

            Program solver = new();
            solver.Solve();
        }
    }
}
  • 算法流程

        初始化所有数组。

        从第一行开始,尝试在每一列放置皇后。

        使用回溯法,如果在某一行找不到安全的位置,则返回到上一行并尝试下一个位置。

        当所有皇后都成功放置时,打印解决方案。

  • 方法分析

        Solve():启动算法,从第一行开始放置皇后。

        PlaceQueen(int row):递归方法,尝试在当前行的每一列放置皇后。如果找到一个安全的位置,则递归地尝试放置下一个皇后。如果所有皇后都已成功放置,则打印解决方案。

        IsSafe(int row, int col):检查在给定位置 (row, col) 放置皇后是否安全。如果列、主对角线和副对角线都没有被占用,则返回 true。

        PrintQueens(int solnum):打印解决方案。对于每一行,如果当前列有皇后,则打印 "Q",否则打印 "*"。

(2)行优先法(Row-First Method):

        与列优先法类似,但不同之处在于,该方法从第一列开始,尝试将皇后放置在每一行。如果当前行没有被攻击,那么就将皇后放置在该行的最右侧。否则,尝试下一行。当找到一个有效的行时,将皇后放置在该行的当前列。重复这个过程,直到所有的皇后都被放置在棋盘上。

// 使用行优先法解决八皇后问题
// 行优先算法也叫回溯法
namespace _144_3
{
    class Program
    {
        static void Main(string[] args)
        {
            ArgumentNullException.ThrowIfNull(args);

            List<int[]> solutions = [];
            int[] solution = new int[8];
            Solve(0, solution, solutions);

            foreach (int[] sol in solutions)
            {
                for (int i = 0; i < 8; i++)
                {
                    for (int j = 0; j < 8; j++)
                    {
                        if (j == sol[i])
                        {
                            Console.Write("Q ");
                        }
                        else
                        {
                            Console.Write(". ");
                        }
                    }
                    Console.WriteLine();
                }
                Console.WriteLine();
            }
        }

        static void Solve(int row, int[] solution, List<int[]> solutions)
        {
            if (row == solution.Length)
            {
                //solutions.Add(solution.ToArray()); // Add a copy of the solution
                solutions.Add([.. solution]);
                return;
            }

            for (int col = 0; col < solution.Length; col++)
            {
                if (IsSafe(row, col, solution))
                {
                    solution[row] = col;
                    Solve(row + 1, solution, solutions);
                }
            }
        }

        static bool IsSafe(int row, int col, int[] solution)
        {
            for (int i = 0; i < row; i++)
            {
                if (solution[i] == col ||
                    Math.Abs(solution[i] - col) == Math.Abs(i - row))
                {
                    return false;
                }
            }
            return true;
        }
    }
}

        代码使用了行优先法(也称为回溯法)来解决八皇后问题,这是一个经典的递归回溯问题。 代码分析:

  • Main 方法

        Main 方法是程序的入口点。

        它首先检查 args 是否为空,如果为空则抛出异常。

        初始化一个空列表 solutions 来存储所有解决方案。

        调用 Solve 方法来寻找解决方案。

        遍历 solutions 列表,并打印出每一个解决方案。

  • Solve 方法

        Solve 方法是递归函数,用于寻找八皇后问题的解决方案。

        如果当前行 row 等于解决方案数组的长度(即8),则找到一个解决方案,并将其添加到 solutions 列表中。

        对于当前行的每一列,检查是否安全(没有冲突),如果安全则在该列放置皇后,并递归调用 Solve 方法处理下一行。

  • IsSafe 方法

        IsSafe 方法用于检查在当前位置 (row, col) 放置皇后是否安全。

        它遍历已经放置皇后的行,检查当前列和左上方对角线是否有冲突。

        如果没有冲突,返回 true;否则返回 false。

  • 注意事项

        在 Main 方法中,使用了 ArgumentNullException.ThrowIfNull(args); 来检查 args 是否为空。这通常用于命令行应用程序,但在没有实际命令行参数需求的程序中是不必要的。

        在 Solve 方法中,使用了 solutions.Add([.. solution]); 来添加解决方案的副本到 solutions 列表。这是C# 9.0引入的切片语法,用于创建数组或列表的浅拷贝。用这个简洁的方式来避免直接添加引用到同一个数组。

(3)对角线优先法(Diagonal-First Method):

        该方法首先选择一个空的棋盘,然后从左上角开始,尝试将皇后放置在对角线上。如果当前对角线没有被攻击,那么就将皇后放置在该对角线的最下方。否则,尝试下一个对角线。当找到一个有效的对角线时,将皇后放置在该对角线的当前列。重复这个过程,直到所有的皇后都被放置在棋盘上。

// 八皇后算法_对角线优先法
namespace _144_2
{
    class Program
    {
        static void Main(string[] args)
        {
            ArgumentNullException.ThrowIfNull(args);

            int n = 8;
            int[] queens = new int[n];
            List<int[]> solutions = [];

            SolveQueens(n, queens, 0, solutions);

            Console.WriteLine("Total solutions: " + solutions.Count);
            foreach (int[] solution in solutions)
            {
                for (int i = 0; i < n; i++)
                {
                    for (int j = 0; j < n; j++)
                    {
                        if (j == solution[i])
                        {
                            Console.Write("Q ");
                        }
                        else
                        {
                            Console.Write(". ");
                        }
                    }
                    Console.WriteLine();
                }
                Console.WriteLine();
            }
        }

        static void SolveQueens(int n, int[] queens, int index, List<int[]> solutions)
        {
            if (index == n)
            {
                solutions.Add([.. queens]);
                return;
            }

            for (int i = 0; i < n; i++)
            {
                if (CanPlaceQueen(queens, index, i))
                {
                    queens[index] = i;
                    SolveQueens(n, queens, index + 1, solutions);
                }
            }
        }

        static bool CanPlaceQueen(int[] queens, int index, int col)
        {
            for (int i = 0; i < index; i++)
            {
                if (queens[i] == col || Math.Abs(queens[i] - col) == index - i)
                {
                    return false;
                }
            }

            return true;
        }
    }
}

        在这个示例中,使用一个整数数组queens来表示棋盘上皇后的位置。queens数组的每个元素表示对应行上皇后的列位置。

        使用递归函数SolveQueens来解决八皇后问题。该函数接受当前皇后的位置、当前行号和已找到的解作为参数。在递归过程中,尝试在每一列上放置皇后,并检查是否满足问题的约束条件。如果满足,则将皇后放置在当前行的对应列上,并继续递归处理下一行。如果当前行的所有列都满足约束条件,则表示找到一个解,并将解添加到已找到的解列表中。

        函数CanPlaceQueen用于检查在给定位置放置皇后是否满足约束条件。它接受棋盘大小、当前皇后的位置、当前行号和当前列号作为参数。在函数中,遍历当前行号之前的行,检查当前列号是否已经放置了皇后,或者当前行和列上的皇后是否在同一条对角线上。如果满足任一条件,则表示不能在当前位置放置皇后。

        在Main函数中,输出找到的解决方案。对于每个解决方案,遍历8行8列,如果当前列是皇后的位置,则输出"Q",否则输出"."。

(4)回溯法(Backtracking):

        该方法通过递归的方式尝试所有可能的皇后位置。算法步骤如下:文章来源地址https://www.toymoban.com/news/detail-842310.html

  • 选择一个空的棋盘。
  • 选择一个皇后,将其放置在棋盘的第一行的任意一列。
  • 选择下一个皇后,将其放置在下一行的任意一列,但不能与第一个皇后位于同一列或同一对角线上。
  • 重复步骤3,直到所有的皇后都被放置在棋盘上。
// 八皇后算法_回溯法
namespace _144
{
    class Program
    {
        #region 八皇后算法
        /// <summary>
        /// 解决八皇后问题
        /// </summary>
        /// <param name="size">皇后数量</param>
        static void QueenArithmetic(int size)
        {
            int[] Queen = new int[size];//每行皇后的位置
            int y, x, i, j, d, t = 0;
            y = 0;
            Queen[0] = -1;
            while (true)
            {
                for (x = Queen[y] + 1; x < size; x++)
                {
                    for (i = 0; i < y; i++)
                    {
                        j = Queen[i];
                        d = y - i;
                        //检查新皇后是否能与以前的皇后相互攻击
                        if ((j == x) || (j == x - d) || (j == x + d))
                            break;
                    }
                    if (i >= y)
                        break;     //不攻击
                }
                if (x == size)     //没有合适的位置
                {
                    if (0 == y)
                    {
                        Console.WriteLine("Over");        //回溯到了第一行
                        break;     //结束
                    }
                    Queen[y] = -1; //回溯
                    y--;
                }
                else
                {
                    Queen[y] = x;   //确定皇后的位置
                    y++;            //下一个皇后
                    if (y < size)
                        Queen[y] = -1;
                    else
                    {
                        Console.WriteLine("\n" + ++t + ':');//所有的皇后都排完了,输出
                        for (i = 0; i < size; i++)
                        {
                            for (j = 0; j < size; j++)
                                Console.Write(Queen[i] == j ? 'Q' : '*');
                            Console.WriteLine();
                        }
                        y = size - 1;//回溯
                    }
                }
            }
            Console.ReadLine();
        }
        #endregion

        static void Main(string[] args)
        {
            ArgumentNullException.ThrowIfNull(args);

            int size = 8;           //皇后数
            QueenArithmetic(size);
        }
    }
}

到了这里,关于C#八皇后算法:回溯法 vs 列优先法 vs 行优先法 vs 对角线优先法的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 矩阵对角线元素求和

    输入一个5×5的数组,分别求其主对角线和辅对角线上元素之和。 输入: 5×5的数组 输出: 主对角线和辅对角线上元素之和 输入样例: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 输出样例: 65 65 提示: 主对角线为从矩阵的左上角至右下角的连线,在数组中即指行列下

    2024年02月04日
    浏览(57)
  • LC 对角线遍历

    给你一个大小为 m x n 的矩阵 mat ,请以对角线遍历的顺序,用一个数组返回这个矩阵中的所有元素。 示例一: 本题对空间复杂度无要求,我们可以申请额外的空间来解题。 标准思路: 仔细观察我们发现偶数对角线向上遍历,奇数列向下遍历,所以我们的代码就可以按照这个

    2024年01月21日
    浏览(45)
  • 矩阵对角线元素的和

    题目: 给你一个正方形矩阵 mat ,请你返回矩阵对角线元素的和。 请你返回在矩阵主对角线上的元素和副对角线上且不在主对角线上元素的和。 示例: 输入:mat = [[1,2,3],             [4,5,6],             [7,8,9]] 输出:25 解释:对角线的和为:1 + 5 + 9 + 3 + 7 = 25 请注意

    2024年02月15日
    浏览(54)
  • 用对角线去遍历矩阵

    声明 该系列文章仅仅展示个人的解题思路和分析过程,并非一定是优质题解,重要的是通过分析和解决问题能让我们逐渐熟练和成长,从新手到大佬离不开一个磨练的过程,加油! 原题链接 用对角线遍历矩阵 https://leetcode.cn/leetbook/read/array-and-string/cuxq3/ 算法分析 图一 图二

    2024年02月13日
    浏览(33)
  • 7-3 矩阵对角线互换

    本题目要求读入1个n×n的矩阵A,然后输出该矩阵正对角线与反对角线互换后的矩阵。具体过程如下图所示: 输入格式: 输入在一行中给出1个不超过1000的正整数n。 输出格式: 输出对角线互换后的矩阵。 输入样例: 输出样例: 在这里给出相应的输出。例如: 代码示例: 

    2024年02月05日
    浏览(47)
  • 矩阵对角线求和(c语言)

    求一个3×3矩阵对角线元素之和。 矩阵 主对角线 副对角线 元素和  

    2024年02月03日
    浏览(52)
  • 1572. 矩阵对角线元素的和

    给你一个正方形矩阵 mat,请你返回矩阵对角线元素的和。 请你返回在矩阵主对角线上的元素和副对角线上且不在主对角线上元素的和。 同时求对角线和副对角线上元素的和再减去重合的元素

    2024年02月13日
    浏览(40)
  • 【1572. 矩阵对角线元素的和】

    来源:力扣(LeetCode) 描述: 给你一个正方形矩阵 mat ,请你返回矩阵对角线元素的和。 请你返回在矩阵主对角线上的元素和副对角线上且不在主对角线上元素的和。 示例 1: 示例 2: 示例 3: 提示: n == mat.length == mat[i].length 1 = n = 100 1 = mat[i][j] = 100 方法一:遍历矩阵 思路

    2024年02月12日
    浏览(39)
  • Leetcode 1572.矩阵对角线元素之和

    给你一个正方形矩阵  mat ,请你返回矩阵对角线元素的和。 请你返回在矩阵主对角线上的元素和副对角线上且不在主对角线上元素的和。 示例  1: 示例  2: 示例 3: 提示: n == mat.length == mat[i].length 1 = n = 100 1 = mat[i][j] = 100 通过次数 63.3K 提交次数 75.9K 通过率 83.3% 1.给一个

    2024年02月10日
    浏览(46)
  • C语言-求矩阵的对角线之和

    其实这种题往往规律性很强,用笔画一画相信都能发现突破口,下面我就讲最简单的方法去求解。 先画图  无非两种情况,n*n,n要么是双数,即对2求余等于0,要么是单数,对2求余不为0;单数和双数的区别在于,单数的情况下两条对角线会有一个交点,当我们计算了一条对

    2024年02月11日
    浏览(73)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包