• 八皇后问题(c#)


    都是老掉牙的东西了。写这篇只是整理下自己的思路。不知道八皇后问题的见 百度文库

    分析1:

      何为横向、纵向、斜向不冲突? 前两个很容易理解。斜向呢?翻译成数学就是任意两个皇后所在的位置所形成的线(两点一线)的斜率不能为1或者-1;

      如何遍历整个棋盘? 最简单的就是八重循环来遍历每行。再在重循环中遍历改行的每一列。

      模拟放置: 遍历第0行,先放置(0,0)位置 判断安全;

            遍历第1行, 放置(1,0),不安全。    放置(1,1) ,还是不安全。     放置(1,2) ,安全;

            遍历第2行。。。。。

       何为安全、不安全? 判断是否安全时,都需要与已前面已放置的皇后进行条件判断。既然是已放置的皇后,那么肯定要选择存放皇后的数据结构。采用二维数组还是什么?由于每行只能放置一个皇后,我们只要知道某行、某列放置了皇后就OK。对应整数数组int[]已经足够,(即下标表示行,值表示列。 如Queen[row] =col ,表示row行col列 放置了皇后。)。  在a行,b列放置一枚皇后时,如果发现符合如下条件。都视为不安全。

      1.不能为同行,因为数据结构能采用Int[] 的前提是不能为同行。免去判断。

      2.不能为同列, Queen[row]=col 中的任意col=b;

      3.不能为斜向, Queen[row]=col 中任意  (col-b)/(row-a)=1 或者  (col-b)/(row-a)=-1;

        代码如下:

            /// <summary>
    /// 判断某行某列是否安全。
    /// </summary>
    /// <param name="a"></param>
    /// <param name="b"></param>
    /// <returns></returns>
    public bool IsSafe(int a, int b)
    {
    for (int row = 0; row < a; row++)//遍历前面的行,后面的还没放。不需要遍历。
    {
    if (b == Queen[row])//同列
    {
    return false;
    }
    if (b - Queen[row] == a - row || b - Queen[row] == row - a)//斜列
    {
    return false;
    }
    }
    return true;
    }

    放置函数:

            public void PlaceQueen_For()
    {
    for (int col0 = 0; col0 < 8; col0++)//遍历第0行的每列
    {
    if (IsSafe(0, col0))//
    {
    Queen[0] = col0;//把安全位置存放起来,
    for (int col1 = 0; col1 < 8; col1++)//遍历第1行的每列
    {
    if (IsSafe(1, col1))
    {
    Queen[1] = col1;
    for (int col2 = 0; col2 < 8; col2++)
    {
    if (IsSafe(2, col2))
    {
    Queen[2] = col2;
    for (int col3 = 0; col3 < 8; col3++)
    {
    if (IsSafe(3, col3))
    {
    Queen[3] = col3;
    for (int col4 = 0; col4 < 8; col4++)
    {
    if (IsSafe(4, col4))
    {
    Queen[4] = col4;
    for (int col5 = 0; col5 < 8; col5++)
    {
    if (IsSafe(5, col5))
    {
    Queen[5] = col5;
    for (int col6 = 0; col6 < 8; col6++)
    {
    if (IsSafe(6, col6))
    {
    Queen[6] = col6;
    for (int col7 = 0; col7 < 8; col7++)
    {
    if (IsSafe(7, col7))
    {
    Queen[7] = col7;

    var a= (int[]) Queen.Clone();//克隆一份当前放置方法。
    List.Add(a);//List 为List<int[]>结构 。用来存放成功解法的放置方法。
    }
    }
    }
    }
    }
    }
    }
    }
    }
    }
    }
    }
    }
    }
    }
    }
    }

    分析2:上面的解法虽然已经能解出答案。但是可扩展性相当差。 如果是10皇后、12皇后呢?再者,我们发现每层FOR循环非常类似。是否可以采用递归?

        提取上面的循环代码如下:

        

            /// <summary>
    /// 某行放皇后。
    /// </summary>
    /// <param name="row"></param>
    public void PlaceQueen(int row)
    {
    if (row >= Size)//成功解法。已经放置了N个安全的皇后。(Size为初始时的N皇后)
    {
    //记录放置方法。
    int[] cloneQueen = (int[])Queen.Clone();
    List.Add(cloneQueen);

    return;
    }

    for (int col = 0; col < Size; col++)//遍历每一列
    {
    if (IsSafe(row, col))
    {
    Queen[row] = col;
    PlaceQueen(row + 1);
    }
    }
    }

      运行时运行 PlaceQueen(0)  就可以获得解。 

      纵观前面的两种方法。其实是换汤不换药。对于N>12时。计算速度有点慢了。可以进行一些优化。譬如运用对称性 ,将遍历次数减少一半。

      其实该函数已经优化了很多。如果当时存放皇后的数据结构采用二维数组。IsSafe()函数将更复杂。

    分析三

      上述函数中,我们查看下消耗时间多的原因。由于是查所有解法,遍历次数肯定是需要 n的n次方。但是每一次中都需要判断IsSafe()函数。虽然已经将IsSafe()函数优化(只判断了已放置的皇后。)。真的有必要需要每一次都判断么?当在row行col列放置一皇后后。再row+1 行 的col-1 ,col ,col+1 都不能再放。 row+2 行的 col-2,col ,col+2 都不能再放,以此类推。

    而这些不能再放的位置如果能预处理。那么IsSafe()函数将完全没必要存在。每行的可放位置都已经提前知道了。

    牛人上场: N皇后的位运算版 参考来源 http://www.matrix67.com/blog/archives/266

      c#版代码

            private static int upperlim = (1 << 8) - 1;// 1111 1111
    private static int sum = 0;
    public static void Test(int row, int ld, int rd)
    {
    if (row != upperlim)
    {
    int pos = upperlim & ~(row | ld | rd);
    while (pos != 0 )
    {
    int p = pos & -pos;//取最近一个可放位置。
    pos = pos - p;//还剩下的可放位置。
    Test(row + p, (ld + p) << 1, (rd + p) >> 1);
    }
    }
    else
    {
    sum++;
    }
    }

      说实话,位运算版本的可读性真的不高。不过对于N皇后问题 能找到如此好的“数据结构” 来处理该问题。真是太牛了。

    其他参考:http://www.cnblogs.com/jillzhang/archive/2007/10/21/922830.html

      




      

        

       

  • 相关阅读:
    JavaScript继承详解 转
    Chinese Consumer and Websites
    【转载】C#防SQL注入过滤危险字符信息
    记一次在数据库中查询:“包含”或者“仅包含”某些商品的订单的方法
    IE 6 position: relative + li 问题
    【转】c# 位操作
    基于asp.net MVC的无刷新文件上传
    C++ 类继承内存布局
    美杜杉 主动防御最新版
    [转]COM 连接点
  • 原文地址:https://www.cnblogs.com/xinjian/p/2206498.html
Copyright © 2020-2023  润新知