趣味编程:用LINQ求解八皇后问题

C#源码摘自 CSDN论坛.NET技术贴:从n皇后问题看Linq的对算法思想的清晰表达力,原作者sp1234。
注:变量名及程序逻辑稍有改动,求解部分加上了注释。
 

C#代码

using System; using System.Collections.Generic; using System.Linq; namespace ConsoleApplication1 { public class Queen { public int row; public int col; } class Program { static IEnumerable<IEnumerable<Queen>> Queens(int r, int maxCol) { return r < 1 ? //递归的终止条件:第0行没有解 new Queen[][] { new Queen[0] } : //外层循环:qs为一维数组,表示单个解,其中存放了前r-1行中各个皇后的位置 from qs in Queens(r - 1, maxCol) //内层循环:c表示棋盘的各个纵列 from c in Enumerable.Range(1, maxCol) //过滤条件:第r行的皇后不能与前r-1行中的任何一个皇后处在同一列、同一条斜线上 where !qs.Any(q => q.col == c || Math.Abs(r - q.row) == Math.Abs(c - q.col)) //将过滤后第r行的合法位置(r,c)加入到已有的解qs当中 select qs.Concat(new [] { new Queen { row = r, col = c } }); } static IEnumerable<IEnumerable<Queen>> Queens(int boardSize) { return Queens(boardSize, boardSize); } static void Main(string[] args) { Queens(8) .ToList() .ForEach(result => { result.ToList().ForEach(q => { Console.Write("{0} ", q.col); }); Console.WriteLine(); }); } } } //输出:共92个解(以下每一行代表一个解,数据的含义为各行中皇后所处的纵列) //1 5 8 6 3 7 2 4 //1 6 8 3 7 4 2 5 //1 7 4 6 8 2 5 3 //1 7 5 8 2 4 6 3 //... //... //... //8 2 4 1 7 5 3 6 //8 2 5 3 1 7 4 6 //8 3 1 6 2 5 7 4 //8 4 1 3 6 2 7 5
代码说明
  1. 代码中带两个参数的Queens函数(第16~29行)是求解八皇后问题的核心函数。
  2. 函数采用递归方式求解,其主体部分只包含一句LINQ语句,非常简洁。
  3. 参数r表示当前调用被用于寻找第r行皇后的位置。(任意两个皇后都不能处在同一行中,因此每一行最多只能有一个皇后)
  4. 参数maxCol表示棋盘的宽度。
  5. 函数返回一个两维数组,数组第一维表示各个解,而第二维则用于存放单个解中各个皇后的位置。
采用LINQ求解,解法固然清晰简洁,但同时也存在着不可调试、不易理解的缺点,为此以下特提供
 

可调试的Queens函数(完全不用LINQ的“传统”版本)

static IEnumerable<IEnumerable<Queen>> Queens(int r, int maxCol) { var result = new List<List<Queen>>(); if (r < 1) //递归的终止条件:第0行没有解 result.Add(new List<Queen>()); else //外层循环:qs为一维数组,表示单个解,其中存放了前r-1行中各个皇后的位置 foreach (var qs in Queens(r - 1, maxCol)) //内层循环:c表示棋盘的各个纵列 for (var c = 1; c <= maxCol; c++) { //过滤条件:第r行的皇后不能与前r-1行中的任何一个皇后处在同一列、同一条斜线上 foreach (var q in qs) if (q.col == c || Math.Abs(r - q.row) == Math.Abs(c - q.col)) goto next_c; //将过滤后第r行的合法位置(r,c)加入到已有的解qs当中 var qs2 = new List<Queen>(qs); qs2.Add(new Queen { row = r, col = c }); result.Add(qs2); next_c: ; } return result; }以备参考。
 

补记:F#版本

open System let rec queens r maxCol = if r < 1 then //递归的终止条件:第0行没有解 [[]] else //外层循环:qs为一维数组,表示单个解,其中存放了前r-1行中各个皇后的位置 queens (r-1) maxCol |> List.map (fun qs -> //内层循环:c表示棋盘的各个纵列 [1..maxCol] |> List.choose (fun c -> //过滤条件:第r行的皇后不能与前r-1行中的任何一个皇后处在同一列、同一条斜线上 if qs |> List.exists (fun (qr : int, qc : int) -> qc = c || Math.Abs(r - qr) = Math.Abs(c - qc)) then None //将过滤后第r行的合法位置(r,c)加入到已有的解qs当中 else Some(qs @ [(r,c)]) ) ) |> List.concat let printQueens boardSize = queens boardSize boardSize |> List.iter (fun result -> result |> List.iter (fun (_, c) -> printf "%d " c) printfn "" ) printQueens 8

你可能感兴趣的:(编程,c,Class,LINQ,fun)