使用Racket,并避免任何有状态的功能(以感叹号结尾的功能),我试图获得所有"对角线条"在列表列表中,如果更容易,则使用向量。
这是解决" N-Queens"国际象棋问题,但我不想看到破坏者如何解决整个问题。相关性是我试图确定是否有任何女王可以攻击任何其他女王对角。我想我可以按照水平和垂直攻击的方式进行操作 - 将每行或每列转换为自己的列表,看看该列表中是否存在多个Queen。
然而,创建斜条带变得非常难看和复杂的代码!必须有一个很好,简洁的方法来解决这个问题。
示例:
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
我想从此形成以下列表:
'(1 6 11 16) '(2 5) '(2 7 12) '(3 6 9) '(3 8) '(4 7 10 13) '(5 10 15)
'(9 14) '(8 11 14) '(12 15)
我注意到这些列表的格式是其他元素比前一个元素多(+ n 1)
,或者比前一个元素多(- n 1)
,但边界检查其他问题使我的代码太复杂,并且不太可能解决合理的解决方案。 (在这种情况下,n
是一维的长度。)
我是以错误的方式来做这件事的吗?是否有更简单的方法来检查对角线是否受到另一位女王的威胁?或者这是正确的想法,但我错过了一些方便的功能,这使得这一切都比我想的更简单?
答案 0 :(得分:2)
一些想法:
当然,无论如何,您可以通过list-ref
编写一个引用列表上的索引的解决方案,但它不会高效/优雅。或者您可以使用list->vector
将列表转换为向量,使用vector-ref
编写基于索引的解决方案,然后返回到包含vector->list
的列表
例如,您可以尝试以下解决方案(改编自此post)。它接收矢量矢量作为输入(如果你想使用列表列表作为输入,只需用vector-ref
替换list-ref
,它的效率会低一些),并返回一个列表列表对角线。元素以不同的顺序添加,但值是正确的(读者练习:格式化输出,使其与问题中的样本匹配)。注意我是如何使用iterations and comprehensions进行循环的,这是惯用的Racket,适用于严重依赖索引的这类问题:
; Returns a list of lists with all the diagonals in a square matrix
; omitting the diagonals that have a single element
; m: the matrix represented as a vector of vectors
; n: the number of rows (or columns, because it's square)
(define (diagonals m n)
; join two results
(append
; first: the leading diagonals
(for/list ([slice (in-range 1 (- (* 2 n) 2))])
(let ((z (if (< slice n) 0 (add1 (- slice n)))))
(for/list ([j (in-range z (add1 (- slice z)))])
(vector-ref (vector-ref m (sub1 (- n j))) (- slice j)))))
; second: the antidiagonals
(for/list ([slice (in-range 1 (- (* 2 n) 2))])
(let ((z (if (< slice n) 0 (add1 (- slice n)))))
(for/list ([j (in-range z (add1 (- slice z)))])
(vector-ref (vector-ref m j) (- slice j)))))))
您可以按如下方式测试它,它按预期工作:
(define matrix '#(#(1 2 3 4) #(5 6 7 8) #(9 10 11 12) #(13 14 15 16)))
(diagonals matrix 4)
=> '((14 9)
(15 10 5)
(16 11 6 1)
(12 7 2)
(8 3)
(2 5)
(3 6 9)
(4 7 10 13)
(8 11 14)
(12 15))