我是编程的新手。我学习红宝石而且我遇到了一个hackerearth问题:不是整个解决方案,而只是我的程序速度... 问题是在n * n板上放置一个n(棕色)的皇后带递归。 这是我提交的解决方案:
{{1}}
我使用的是while而不是每个因为我读它有点快但是...... 如果你能提供帮助,我会很感激,并且肯定会将我的技能提升到更好的水平。 感谢
答案 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 |]