算法回顾--N皇后问题简单回顾

前言

最近学习的过程中,不知道哪门子的思维发散,突然又遇见皇后问题了,于是乎老调重弹,心里琢磨,虽然思路大家都容易懂,哪怕是最简单的野蛮回溯法,说着简单,但是如果非得编码实现?我可以一次性写出来OK的代码吗?我对此表示疑问,于是乎动手写代码,发现写此类算法问题,最重要的是边界条件的判断。这里说明一下,这篇纯属练手,不考虑算法效率,只是为了实现,为了练习最暴力野蛮的回溯,说白了,就是怎样简单粗暴的玩弄for和while这些个玩意!

实现

本人比较懒,所以懒得搞二维数组来存储皇后坐标,其实用二维数组来存储,然后根据行列来遍历和匹配,确实效率高了不少,但是,我在这里仅仅只是练习回溯的思想,所以只是使用简单的数组来存储N*N个数,比如8皇后问题,我就用数组来存储 {1,2,3,,,,,,,,,,64},然后使用queens数组存储安全的皇后

代码

/// <summary>

/// 皇后算法非递归实现,主要思想如下:

/// 初始化皇后备选列表为空(安全),将所有坐标的棋子尝试放入

/// 如果符合安全,则放入(如果数目达到则保留输出),如果不安全则跳过继续搜索

/// 如果搜索到结尾依然未搜到,则循环向上回溯到上一次解的下一个继续

/// </summary>

public class Queen

{

    // 矩阵维度

    int size;

    // 从1编号,存放所有整数

    int[] array;

    int count;



    public Queen()

        : this(4)

    {

    }



    public Queen(int s)

    {

        this.size = s;

        InitList();

    }



    private void InitList()

    {

        count = size * size;

        array = new int[count];

        for (int i = 0; i < count; i++)

        {

            array[i] = i + 1;

        }

    }



    public void PrintQueenResult()

    {

        List<int> queens = new List<int>();



        // 记录探测索引

        int tryIndex = 0;

        // 记录最后一次皇后解

        int lastQueen = 0;

        // 记录皇后总数

        int queenCount = 0;

        // 记录所有全皇后解个数

        int solutions = 0;

        while (true)

        {

            // 探测元素

            int tryItem = array[tryIndex];



            // 如果探测到最后一个元素,并且皇后已经回溯为空

            // 表示回溯已经全部完成,返回

            if (tryItem == array[count - 1] && queenCount == 0)

                break;



            // 找到安全的皇后

            if (IsSafe(queens, tryItem))

            {

                queens.Add(tryItem);

                // 皇后数加1

                queenCount++;

                // 记录最后一次放置的皇后

                lastQueen = tryItem;



                // 如果皇后获取足够,输出

                if (queenCount == size)

                {

                    Console.WriteLine("找到皇后排列:{0}",

                        string.Join(",", queens));

                    solutions++;

                }

            }

            else

            {

                if (tryIndex < count - 1)

                {

                    // 如果不安全,还未搜索结束,继续搜索

                    tryIndex++;

                }

                else

                {

                    // 如果不安全,但搜索结束,则回溯

                    while (tryIndex >= count - 1)

                    {

                        queens.Remove(lastQueen);

                        queenCount--;

                        tryIndex = lastQueen;



                        // 如果回溯完毕则跳出

                        if (queenCount == 0)

                            break;



                        lastQueen = queens[queenCount - 1];

                    }

                }

            }

        }



        Console.WriteLine("全部解个数为:{0}", solutions);

    }



    private bool IsSafe(List<int> list, int target)

    {

        if (list == null || list.Count == 0)

            return true;

        return list.All(d => !IsDangerous(d, target));

    }



    private bool IsDangerous(int a, int b)

    {

        int rowA = (a - 1) / size + 1;

        int rowB = (b - 1) / size + 1;

        int colA = (a - 1) % size + 1;

        int colB = (b - 1) % size + 1;



        if (a == b) return true;

        if (rowA == rowB) return true;

        if (colA == colB) return true;

        if (Math.Abs(rowA - rowB) == Math.Abs(colA - colB))

            return true;



        return false;

    }



    private int Pop(List<int> list)

    {

        int last = list[list.Count - 1];

        list.Remove(last);

        return last;

    }



    private int Peek(List<int> list)

    {

        return list[list.Count - 1];

    }

}

测试

八皇后测试代码:Queen q = new Queen(8);  q.PrintQueenResult();

结语

脑子不练会生锈,还是要经常做做这些最基础的东西,把不习惯变成习惯,慢慢来,不早了,先睡了

你可能感兴趣的:(算法)