红宝石的递归太慢了

时间:2017-01-09 15:27:11

标签: ruby recursion

我是编程的新手。我学习红宝石而且我遇到了一个hackerearth问题:不是整个解决方案,而只是我的程序速度... 问题是在n * n板上放置一个n(棕色)的皇后带递归。 这是我提交的解决方案:

{{1}}

我使用的是while而不是每个因为我读它有点快但是...... 如果你能提供帮助,我会很感激,并且肯定会将我的技能提升到更好的水平。 感谢

1 个答案:

答案 0 :(得分:1)

现在,我们都是64位无符号整数和64位操作系统的拥有者,N> 8真的很烦人。也许我应该等到我在x128平台上,F#有一个uint128,然后回答问题......

开玩笑说。一旦你编写了一个优化的程序,直截了当的方法并不总能做到。您可以节省预计算时间和创建查找表的时间,从而减少内部循环/递归所需的时间。

下面的代码在大约8ms内加载(并预先计算查找表)并在我的机器上解决N = 8的nqueens大约2ms。它是一种.NET语言,而不是一些本机代码。它在fsi(交互式shell)中运行。

它使用位板(使用uint64可以很好地工作到N = 8)。

技巧是,如果你将k个皇后放在k列上,你可以在(k + 1)递归中过滤不受先前定位的k皇后威胁的行。因此,您获得的深度越多,您在搜索中必须考虑的行数就越少(在某种程度上提高了算法的复杂性)。

对于N&gt; 8,你可以尝试做同样的事情,并使用板2 uint64值(10 * 10 = 100 <128)。就像在32位机器上的旧国际象棋编程日一样,人们使用2 uint32作为位板......

  

nqueens 8 ;;
  实时:00:00:00.002,CPU:00:00:00.000,GC gen0:0,gen1:0,gen2:0
  val it:int [] option = Some [| 0; 4; 7; 5; 2; 6; 1; 3 |]

现在,我不知道Ruby与F#相比有多快,但我怀疑你无法提出满足黑客网站时序要求的解决方案,即使你需要的东西效率低于我的代码位板使用

因此,下面的代码可能会为您提供从优化Ruby代码开始的想法。 (抱歉 - 我对Ruby一无所知......)

let binary (v : uint64) (tw : System.IO.TextWriter)  =
    let mask : uint64 = 0x1UL <<< 63
    let rec printDigit m c =
        if c % 8 = 0 then tw.WriteLine()
        match m with
        | 0UL -> ()
        | _ -> 
            if m &&& v <> 0UL then
                tw.Write("1")
            else 
                tw.Write("0")
            printDigit (m >>> 1) (c+1)
    printDigit mask 0

let showMask (m : uint64) =
    printfn "%t" (binary m)

let squareIndexBig n col row = row * n + col

let squareIndex col row = row * 8 + col

let squareMaskBig n col row =
    bigint.One <<< squareIndexBig n col row

let squareMask col row = 1UL <<< squareIndex col row

let diagMovesBig n col row =
    let mutable c = col
    let mutable r = row
    let mutable b = bigint.Zero
    while c > -1 && row > -1 do
        b <- b ||| squareMaskBig n c r
        c <- c - 1
        r <- r - 1
    c <- col
    r <- row
    while c < n && r < n do
        b <- b ||| squareMaskBig n c r
        c <- c + 1
        r <- r + 1
    c <- col
    r <- row
    while c > -1 && r < n do
        b <- b ||| squareMaskBig n c r
        c <- c - 1
        r <- r + 1
    c <- col
    r <- row
    while c < n && r > -1 do
        b <- b ||| squareMaskBig n c r
        c <- c + 1
        r <- r - 1
    b

let diagMoves col row =
    let mutable c = col
    let mutable r = row
    let mutable b = 0UL
    while c > -1 && row > -1 do
        b <- b ||| squareMask c r
        c <- c - 1
        r <- r - 1
    c <- col
    r <- row
    while c < 8 && r < 8 do
        b <- b ||| squareMask c r
        c <- c + 1
        r <- r + 1
    c <- col
    r <- row
    while c > -1 && r < 8 do
        b <- b ||| squareMask c r
        c <- c - 1
        r <- r + 1
    c <- col
    r <- row
    while c < 8 && r > -1 do
        b <- b ||| squareMask c r
        c <- c + 1
        r <- r - 1
    b

let nlowerbits n =
    let mutable v  = 0x01UL
    for i in [1..n] do
        v <- (v <<< 1) ||| 1UL
    bigint v

let nbitswideOne n =
    let mutable v  = bigint.One
    for i in [1..n] do
        v <- (v <<< n) ||| bigint.One
    v


let row0CodeBig n = 
    [|
        for r in 0..n-1 do
            yield (nlowerbits n) <<< (n * r)
    |]


let row0Code = 
    [|
        for r in 0..7 do
            yield 0b11111111UL <<< (8 * r)
    |]

let col0CodeBig n =
    [|
        for c in 0..n-1 do
            yield nbitswideOne n <<< c
    |]

let col0Code = 
    [|
        for c in 0..7 do
            yield 0b0000000100000001000000010000000100000001000000010000000100000001UL <<< c
    |]

let diagCodeBig n =
    [|
        for col in 0..n-1 do
            yield 
                [|
                    for row in 0..n-1 do
                        yield diagMovesBig n col row
                |]
    |]


let diagCode = 
    [|
        for col in 0..7 do
            yield 
                [|
                    for row in 0..7 do
                        yield diagMoves col row
                |]
    |]

let placeQueenBig n col row =
    (row0CodeBig n).[row] ||| (col0CodeBig n).[col] ||| (diagCodeBig n).[col].[row]

let placeQueen col row =
    row0Code.[row] ||| (col0Code.[col]) ||| (diagCode.[col].[row])

let squareSafeBig n board col row =
    bigint.Zero = (board &&& squareMaskBig n col row)

let squareSafe board col row =
    0UL = (board &&& squareMask col row)

let nqueensBig n =
    let queenRows : int[] = Array.zeroCreate n
    let assign col row = queenRows.[col] <- row

    let rec place board col =
        //showMask board
        match col with
        | x when x = n -> true
        | _ ->
            [0..n-1]
            |> List.filter (fun row -> squareSafeBig n board col row)
            |> List.tryFind (fun row -> place (board ||| placeQueenBig n col row) (col+1))
            |> fun row -> 
                    match row with
                    | None -> false
                    | Some r ->
                        assign col r
                        true

    if place (bigint.Zero) 0
    then
        Some queenRows
    else
        None


let nqueens n =
    let queenRows : int[] = Array.zeroCreate n
    let assign col row = queenRows.[col] <- row

    let rec place board col =
        //showMask board
        match col with
        | x when x = n -> true
        | _ ->
            [0..n-1]
            |> List.filter (fun row -> squareSafe board col row)
            |> List.tryFind (fun row -> place (board ||| placeQueen col row) (col+1))
            |> fun row -> 
                    match row with
                    | None -> false
                    | Some r ->
                        assign col r
                        true

    if place 0UL 0
    then
        Some queenRows
    else
        None

<强>更新

在F#中使用System.Math.BigInteger也称为bigint,我使用nqueensBig n函数扩展了代码,该函数也解决了N&gt;的问题。 8。 性能不像nqueens n那样炽热,而且没有堆操作,但我认为仍然足够快。

  

nqueensBig 10 ;;
  Real:00:00:00.071,CPU:00:00:00.078,GC gen0:10,gen1:1,gen2:0
  val it:int [] option = Some [| 0; 2; 5; 7; 9; 4; 8; 1; 3; 6 |]

     

nqueensBig 13 ;;
  Real:00:00:00.167,CPU:00:00:00.171,GC gen0:23,gen1:0,gen2:0
  val it:int [] option = Some [| 0; 2; 4; 1; 8; 11; 9; 12; 3; 5; 7; 10; 6 |]