首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > .NET > .NET >

F#(FSharp)用三种方法解N皇后有关问题,剖析F#之美

2011-12-24 
F#(FSharp)用三种方法解N皇后问题,剖析F#之美由于论坛不易于排版,所以具体内容请看这里,欢迎转载、拍砖!htt

F#(FSharp)用三种方法解N皇后问题,剖析F#之美
由于论坛不易于排版,所以具体内容请看这里,欢迎转载、拍砖!
http://blog.csdn.net/aimeast/archive/2010/04/25/5527749.aspx

代码先贴出:

C# code
let NQueens n =      let a = [|for i in 0..n -> true|]   //某列是否使用的标志      let b = [|for i in 0..(2 * n - 1) -> true|] //斜负方向上是否使用的标志      let c = [|for i in 0..(2 * n - 1) -> true|] //斜正方向上是否使用的标志      let path = [|for i in 0..n -> 0|]   //记录当前路径      //Solve n j 求解规模为n,第j行的解      let rec Solve n j =          if j > n then   //已经把当前状态的n行都求解完毕,可打印当前路径              printfn "%A" path.[1..] //打印当前结果          else    //否则,要继续向下求解              for i in 1..n do    //枚举当前行的所有列                  //如果当前位置的列、斜正、斜负方向都可用,则使用                  if (a.[i] && b.[i + j - 1] && c.[n - i + j]) then                      //标记状态                      a.[i] <- false                      b.[i + j - 1] <- false                      c.[n - i + j] <- false                      path.[j] <- i   //记录当前路径                      do Solve n (j + 1)  //求解下一行                      //还原状态                      a.[i] <- true                      b.[i + j - 1] <- true                      c.[n - i + j] <- true      do Solve n 1    //从第一行开始求解      printfn ""    List.iter NQueens [1..10]   //求1到10皇后的所有解  System.Console.ReadKey()|>ignore
C# code
//自定义数据类型  type Queen =      struct          val x: int          val y: int          //构造函数          new(x: int, y: int) = { x = x; y = y }          //重载Object.ToString()          override this.ToString() =              //字符串打印函数              sprintf "(%d,%d)" this.x this.y      end    let NQueens n =      //对子问题求解      let rec Solve = function          //第一行每一个位置都可以放置          | x when x = 1 ->              [for y in 1..n -> [new Queen(1,y)]]          //其他情况          | x ->              //构造一个临时存放结果的变量              let mutable t = [[new Queen(0,0)]].Tail              //枚举当前子问题的解              for i in Solve (x - 1) do                  //逐一尝试是否可以放置                  for y in 1..n do                      if not((List.exists (fun (elem: Queen) -> elem.y = y ) i)   //列可放置                              ||(List.exists (fun elem -> elem = x + y) (List.map (fun (elem: Queen) -> elem.x + elem.y) i))  //斜负方向可放置                              ||(List.exists (fun elem -> elem = x - y) (List.map (fun (elem: Queen) -> elem.x - elem.y) i))) //斜正方向可放置                      then                          //把当前可行解放入临时空间                          t <- t @ ([i @ [new Queen(x, y)]])              //返回当前可行解              t      //求解并返回      Solve n    //打印结果  NQueens 8 |> List.iteri (fun i elem -> printfn "%d:\t%A" (i + 1) elem)  System.Console.ReadKey()|>ignore  
C# code
type Queen =   
    struct 
        val x: int 
        val y: int 
        new(x: int, y: int) = { x = x; y = y } 
        override this.ToString() = 
            sprintf "(%d,%d)" this.x this.y 
    end 
 
let NQueens n = 
    let rec Solve = function 
        | x when x = 1 -> 
            [for y in 1..n -> [new Queen(1,y)]] 
        | x -> 
            //求出当前子问题解集与要测试是否能放置的点的空间 
            [for sub in Solve (x - 1) do 
                for y in 1..n -> (sub, y)] 


            //将此空间传递给选择器选择哪些是有效的 
            |> List.choose (fun (sub, y) -> 
                if not(sub |> List.exists (fun (elem: Queen) -> elem.y = y )    //列有效 
                        ||(List.map (fun (elem: Queen) -> elem.x + elem.y) sub) 
                                |> List.exists (fun elem -> elem = x + y)  //斜负方向有效 
                        ||(List.map (fun (elem: Queen) -> elem.x - elem.y) sub) 
                                |> List.exists (fun elem -> elem = x - y))  //斜正方向有效 
                then Some(sub @ [new Queen(x, y)])  //标记有效值 
                else None)  //不作处理 
    //求解并返回结果 
    Solve n 
 
//求解并打印结果 
NQueens 8 |> List.iteri (fun i elem -> printfn "%d:\t%A" (i + 1) elem) 
System.Console.ReadKey()|>ignore 



[解决办法]
沙发 接分
[解决办法]
bd
[解决办法]
沙发 接分
[解决办法]
LZ可以试试位运算,效率会高很多。
[解决办法]
F#支持函数式程序设计,强调程序应做什么(what),而不是明确地写出应该怎么(how)做。
[解决办法]
F# 的语法和linq如此相似。。。
虽然linq能大量简写代码
但是俺还是不喜欢使用。
一是懒得去学。
二是不易读。
[解决办法]
不论是什么程序,一定要注意的是,如果你执行时是递归的,就幼稚了。比如我们打印前10种解答,求解n皇后算法的前10种解答时你的程序却要首先求解n-1皇后的全部解答,那么这种程序就是丝毫不懂回朔算法解题之道的。回朔算法的关键就是,它不是解决“全部”问题的,而是抽取前n种解答的。
[解决办法]
[ 8 楼 sp1234 的回复:]
不论是什么程序,一定要注意的是,如果你执行时是递归的,就幼稚了。比如我们打印前10种解答,求解n皇后算法的前10种解答时你的程序却要首先求解n-1皇后的全部解答,那么这种程序就是丝毫不懂回朔算法解题之道的。回朔算法的关键就是,它不是解决“全部”问题的,而是抽取前n种解答的。
[]
[解决办法]
探讨
引用:不论是什么程序,一定要注意的是,如果你执行时是递归的,就幼稚了。比如我们打印前10种解答,求解n皇后算法的前10种解答时你的程序却要首先求解n-1皇后的全部解答,那么这种程序就是丝毫不懂回朔算法解题之道的。回朔算法的关键就是,它不是解决“全部”问题的,而是抽取前n种解答的。
请问这段程序是否进行了递归呢?

C# code
static IEnumera……

[解决办法]
以前C#写的一个用位运算求n皇后的程序,不算输出的话,13皇后基本上可以在1秒之内求出来。
F#没用过,不知道是否可以转化一下?

C# code
using System;namespace CSharpTest{    class Program    {        static int[] Place;        static int QueenCount;        static void Main(string[] args)        {            Solve(10);            Console.ReadKey();        }        static void Solve(int length)        {            QueenCount = length;            Place = new int[length];            SearchQueens(0, 0, 0, 0);        }        static void SearchQueens(int currentColumn, int columnCheck, int slashCheck1, int slashCheck2)        {            if (currentColumn == QueenCount)            {                PrintResult();                return;            }            slashCheck1 <<= 1; slashCheck2 >>= 1;            for (int i = 0; i < QueenCount; i++)            {                int sign = 1 << i;                if ((sign & columnCheck) == 0 && (slashCheck1 & sign) == 0 && (slashCheck2 & sign) == 0)                {                    Place[currentColumn] = i + 1;                    SearchQueens(currentColumn + 1, columnCheck | sign, slashCheck1 | sign, slashCheck2 | sign);                }            }        }        static void PrintResult()        {            for (int i = 0; i < QueenCount; i++)                Console.Write("{0} ", Place[i]);            Console.WriteLine();        }    }} 


[解决办法]
學了物件導向的程式語言後再看F#的code真的有點難吸收呀!
[解决办法]
大家都那么积极 我也分享一下以前写的代码吧。还没完善

C# code
 
using System;
using System.Collections.Generic;
using System.Text;

namespace BreaveBoy.ConsoleApplication_Test.Logic
{
  class EightQueen
  {
   
    private char other ;
    private char queen ;
    private char split ;
    private int maxResult;
    private int random;
 
    private bool isLoop;
    private bool isPrint = false;
    private bool isRandom;
    private int flag;
    private bool graphPrint;

    /// <summary>
    /// 默认图形输出
    /// GraphPrint=false为坐标打印
    /// </summary>
    public bool GraphPrint
    {
      get { return graphPrint; }
      set { graphPrint = value; }
    }

    Point[] QueenPosition = new Point[8];
   
    /// <summary>
    /// 是否打印
    /// </summary>
    public bool IsPrint
    {
      get { return isPrint; }
      set { isPrint = value; }
    }
    /// <summary>
    /// 是否循环求解
    /// </summary>
    public bool IsLoop
    {
      get { return isLoop; }
      set { isLoop = value; }
    }
    /// <summary>
    /// 是否随机求解
    /// </summary>
    public bool IsRandom
    {
      get { return isRandom; }
      set { isRandom = value; }
    }
    /// <summary>
    /// 求解方式(1:遍历求解,2:删选求解)
    /// </summary>
    public int Flag
    {
      get { return flag; }
      set { flag = value; }
    }

    /// <summary>
    /// 皇后位置默认为8皇后
    /// </summary>
    public EightQueen()
    {
      other = '*';
      queen = 'Q';
      split = '\t';
      random = 0;
      graphPrint = true;
      maxResult = FindResult(2, 0);
    }
    /// <summary>
    /// n皇后求解
    /// </summary>
    /// <param name="flag">求解方式(1:遍历求解,2:删选求解) </param>
    /// <param name="x">求第x种解 </param>
    /// <returns> </returns>
    public  int FindResult(int flag,int x)
    {
      int ret=0;
      int all = 0;
      x = (x == 0 ? 0 : (x % maxResult));
      if (flag % 2 == 1)
      {
        for (int i = 0; i < 8; i++)
        {
          QueenPosition[0] = new Point(i, 0);
          for (int j = 0; j < 8; j++)


          {
            QueenPosition[1] = new Point(j, 1);
            for (int k = 0; k < 8; k++)
            {
              QueenPosition[2] = new Point(k, 2);
              for (int l = 0; l < 8; l++)
              {
                QueenPosition[3] = new Point(l, 3);
                for (int m = 0; m < 8; m++)
                {
                  QueenPosition[4] = new Point(m, 4);
                  for (int n = 0; n < 8; n++)
                  {
                    QueenPosition[5] = new Point(n, 5);
                    for (int o = 0; o < 8; o++)
                    {
                      QueenPosition[6] = new Point(o, 6);
                      for (int p = 0; p < 8; p++)
                      {
                        QueenPosition[7] = new Point(p, 7);
                        if (CheckConflict(QueenPosition, 7))
                        {
                          all++;
                          continue;
                        }
                        else
                        {
                          all++;
                          ret++;
                          if (x  == ret && isPrint)
                            Print(QueenPosition);
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }       
      }
      else
      {
        for (int i = 0; i < 8; i++)
        {
          QueenPosition[0] = new Point(i, 0);
          for (int j = 0; j < 8; j++)
          {
            QueenPosition[1] = new Point(j, 1);
            if (CheckConflict(QueenPosition, 1))


            { all++; continue; }
            for (int k = 0; k < 8; k++)
            {
              QueenPosition[2] = new Point(k, 2);
              if (CheckConflict(QueenPosition, 2))
              { all++; continue; }
              for (int l = 0; l < 8; l++)
              {
                QueenPosition[3] = new Point(l, 3);
                if (CheckConflict(QueenPosition, 3))
                { all++; continue; }
                for (int m = 0; m < 8; m++)
                {
                  QueenPosition[4] = new Point(m, 4);
                  if (CheckConflict(QueenPosition, 4))
                  { all++; continue; }
                  for (int n = 0; n < 8; n++)
                  {
                    QueenPosition[5] = new Point(n, 5);
                    if (CheckConflict(QueenPosition, 5))
                    { all++; continue; }
                    for (int o = 0; o < 8; o++)
                    {
                      QueenPosition[6] = new Point(o, 6);
                      if (CheckConflict(QueenPosition, 6))
                      { all++; continue; }
                      for (int p = 0; p < 8; p++)
                      {
                        QueenPosition[7] = new Point(p, 7);
                        if (CheckConflict(QueenPosition, 7))
                        {
                          all++;
                          continue;
                        }
                        else
                        {
                          all++;
                          ret++;
                          if (x == ret && isPrint)
                            Print(QueenPosition);
                        }
                      }
                    }


                  }
                }
              }
            }
          }
        }
      }
      Console.WriteLine("\n总共遍历{0}次:成功{1}", all, ret);
      return ret;
    }
 


[解决办法]
C# code
        /// <summary>        /// 检查水平线        private bool CheckHorizontal(Point a, Point b)        {            if (a.Y == b.Y)                return true;            else                return false;        }        /// <summary>        /// 检查竖线        /// </summary>        private bool CheckVertical(Point a, Point b)        {            if (a.X== b.X)                return true;            else                return false;        }        /// <summary>        /// 检查斜线        /// </summary>        private bool CheckOblique(Point a, Point b)        {            if (a.X - b.X == 0)                return false;            if (Math.Abs((float)(a.Y - b.Y) / (a.X - b.X)) == 1)                return true;            else                return false;        }        /// <summary>        /// 检查数组中皇后的位置是否有冲突        /// </summary>        /// <param name="QueenPosition"></param>        /// <param name="to">0<to<8 </param>        /// <returns></returns>        private bool CheckConflict(Point[] QueenPosition,int to)        {            for (int i = 0; i <to; i++)            {                for (int j = i + 1; j <=to; j++)                {                    if (CheckHorizontal(QueenPosition[i], QueenPosition[j])                             ||CheckVertical(QueenPosition[i], QueenPosition[j])                             || CheckOblique(QueenPosition[i], QueenPosition[j]))                        return true;                }            }            return false;        }        /// <summary>        /// 打印一行皇后的位置        /// </summary>        /// <param name="loac">换后所在位置</param>        /// <param name="n">可扩展为n皇后问题</param>        private String PrintOneLine(Point loac,int n)        {            StringBuilder tem = new StringBuilder() ;            for (int i = 0; i < n; i++)            {                tem.Append(split);                if (i == loac.X)                {                    if (graphPrint)                        tem.Append(queen);                    else                        tem.Append(loac.PrintString());                }                                    else                    tem.Append(other);                           }            return tem.Append("\n\n").ToString();        }        /// <summary>        /// 控制台打印皇后        /// *可打印n皇后        /// </summary>        /// <param name="QueenPosition">皇后位置数组</param>        private void Print(Point[] QueenPosition)        {            StringBuilder tem = new StringBuilder();             for (int i = 0; i < QueenPosition.Length; i++)            {                tem.Append(PrintOneLine(QueenPosition[i], QueenPosition.Length));            }            Console.WriteLine(tem.ToString());        }
[解决办法]
C# code
        /// <summary>        /// 测试用例一        /// </summary>        public void Test1()        {            DateTime beginTime = DateTime.Now;            Console.WriteLine("(方法一)\n\tbegin time :" + beginTime);            Console.WriteLine(FindResult(1,0));            DateTime endTime = DateTime.Now;            Console.WriteLine("\tend time :" + endTime);            Console.WriteLine("算法所用时间(单位:毫秒)" + (endTime - beginTime).TotalMilliseconds);        }        /// <summary>        /// 测试用例二        /// </summary>        public  void Test2()        {            DateTime beginTime = DateTime.Now;            Console.WriteLine("(方法二)\n\tbegin time :" + beginTime);            Console.WriteLine(FindResult(2, 0));            DateTime endTime = DateTime.Now;            Console.WriteLine("\tend time :" + endTime);            Console.WriteLine("算法所用时间(单位:毫秒)" + (endTime - beginTime).TotalMilliseconds);        }        /// <summary>        /// 测试用例三        /// </summary>        public void Test3()        {            Point[] p = new Point[] { new Point(0, 0), new Point(1, 2), new Point(2, 4), new Point(3, 1), new Point(4, 5), new Point(5, 7), new Point(6, 3), new Point(7, 6) };            Console.WriteLine(CheckConflict(p, 7));            Console.ReadLine();        }               /// <summary>        /// 测试用例一和二        /// </summary>        public  void Test()        {            Test1();            Test2();            Console.ReadLine();        }        /// <summary>        /// 定制测试用例        /// </summary>        /// <param name="Flag">1:q</param>        public void Run(int Flag)        {             String input="";            while (true)            {                if (IsRandom)                {                    Random rd = new Random();                    random = rd.Next(maxResult);                }                FindResult(Flag, random);                if (!IsLoop)                    break;                Console.WriteLine("退出/继续(q/g)!");                input = Console.ReadLine();                if (input.Equals("q"))                    break;            }        }        class Point        {            int _x, _y;            public int Y            {              get { return _y; }              set { _y = value; }            }            public int X            {                get { return _x; }                set { _x = value; }            }            public Point(int x, int y)            {                X = x;                Y = y;            }            public String  PrintString()            {                return String.Format("({0},{1})", X, Y);            }            public void Print()            {                Console.WriteLine(PrintString());            }        }    }} 

热点排行