1

Lisp の複数の if ステートメントについて質問があります。countが等しくない場合はandステートメントnを続行し、それ以外の場合は実行し、それがnil を返します。letif(= (abs (- row i))t

ただし、常にブロック内のコードの最後の行を返すため、そうcountでない場合はいつでも戻ることがわかりました。ではない場合にのみ、句のいずれかが である場合にのみ戻るようにプログラムを作成する方法を教えてください。nnilprogncountnnilort

(loop for i below n
      do (if (/= count n)
             (progn
               (let ((tcol (getqueencol i n)))
                 (if (or (= col tcol) (= (abs (- row i)) (abs (- col tcol))))
                     (return-from queen-can-be-placed-here nil))))
           (if (= (abs (- row i)))
               (return-from queen-can-be-placed-here nil))))

更新しました:

良い反応をありがとう。はい、確かに私は N クイーン パズルを解こうとしています :P 私が現在抱えている問題は、特定の行と列にクイーンを配置するかどうかを決定するコントロールが、行が空のときに機能しないことです。これは、行が空のときにgetqueencolが返され、そこに.nilqueen-can-be-placed-here(= nil NUMBER)

これに対抗するために、行が空かどうかを知るカウント変数を作成しようとしました。これにより、空の行queen-can-be-placed-hereを呼び出さないようgetqueencolにすることができます。queen-can-be-placed-here問題は、クイーンが空の行に追加されるときにチェックがどのようになるかわからないことです。

これまでのコードは次のとおりです。

(defvar *board* (make-array '(5 5) :initial-element nil)) 

(defun getqueencol (row n)
"Traverses through the columns of a certain row
 and returns the column index of the queen."
  (loop for i below n
        do (if (aref *board* row i)
               (return-from getqueencol i))))

(defun print-board (n)
"Prints out the solution, e.g. (1 4 2 5 3),
 where 1 denotes that there is a queen at the first 
 column of the first row, and so on."
  (let ((solutionlist (make-list n)))
    (loop for row below n
          do (loop for col below n
                   do (when (aref *board* row col)
                        (setf (nth row solutionlist) col))))
    (print solutionlist)))


(defun queen-can-be-placed-here (row col n)
"Returns t if (row,col) is a possible place to put queen, otherwise nil."
  (let ((count 0))
    (loop for i below n  ;This is the block I added to keep track of if a     row is empty (count = n)
          do (if (not (aref *board* row i))   
                 (setf count (+ 1 count))))

    (loop for i below n
          do (if (/= count n)
                 (let ((tcol (getqueencol i n)))
                   (if (or (= col tcol) (= (abs (- row i)) (abs (- col     tcol))))
                       (return-from queen-can-be-placed-here nil)))
               (if (= (abs (- row i)))   ;Here is where I don't know what to check
                   (return-from queen-can-be-placed-here nil)))))

  (return-from queen-can-be-placed-here t))


(defun backtracking (row n)
"Solves the NxN-queen problem with backtracking"
  (if (< row n)
      (loop for i below n
          do (when (queen-can-be-placed-here row i n)
                  (setf (aref *board* row i) 't)
                  (backtracking (+ row 1) n)
                  (setf (aref *board* row i) 'nil)))
    (print-board n)))

(defun NxNqueen-solver (k)
"Main program for the function call to the recursive solving of the problem"
  (setf *board* (make-array (list k k) :initial-element nil))
  (backtracking 0 k))
4

2 に答える 2

2

Lisp の複数の if ステートメントについて質問があります。count が n と等しくない場合は、let ステートメントと if ステートメントを続行します。

ifのいずれかのブランチに複数のフォームを持ち始めると、多くの場合、代わりにcondを使用する方が明確です。

(cond
  ((/= n count)               ; if n is not count, then ...
   (let ...       
     (return-from ...)))      ; maybe return something
  ((= (abs (- row i)) ...)    ; else if |row-i] = ..., 
   (return-from ...)))        ; return nil

そうは言っても、 ifのthen部分に実際には複数のブランチはありませんletprognでラップする必要はありません。あなたはただ行うことができます:

(if (/= count n)
    (let ((tcol (getqueencol i n)))
      (if (or (= col tcol) (= (abs (- row i)) (abs (- col tcol))))
          (return-from queen-can-be-placed-here nil)))
    (if (= (abs (- row i)))
        (return-from queen-can-be-placed-here nil)))

ifからnilを返す場合、考慮すべきことが 2 つあります。return-fromを使用しています。これは、ローカル以外の終了を実行していることを意味します。testが false の場合、フォーム(if test then)の式のnilですが、その値で何もしていません。実際、Common Lisp では、else部分がない場合に使用するかなり一般的なスタイルです。つまり、(when test then)は(if test then nil)および(if test then)と同等です。というのは本当です(もし…)nilと評価されるため、nilletの値、したがってprognの値ですが、 prognの値に対して実際に何もしません。loop内で評価しているのは単なるフォームです。

于 2015-09-25T13:00:02.830 に答える
0

backtrack を呼び出すたびに、考えられる各列にクイーンを配置しようとします。queen-can-be-placed-hereこれは、 rowを呼び出しているときに、その後に続く行を含むすべての行が空であることrowを確認できることを意味します (バックトラック時にボードを消去します)。row row

したがって、列が少ないボードのサブセットを見て、クイーンを現在の列colと現在に正しく配置できるかどうかを確認するだけで済みます。row

             col
              v
           c0 v  c1

   r0      Q  -  -  -
   r1      -  -  Q  -
  row >>   -  ?  -  -
           -  -  -  -

のすべての行について、正対角位置guetqueencolとは異なるか、直接対角の位置にある列を返す場合にのみ、クイーンが存在する可能性がありますcol( を使用した計算abs)。したがって、実際には何もカウントする必要はありません。テストが決して満たされないことを確認してください。

変数名などのコードには小さな問題があるため、すべてが意図したとおりに機能することを確認したら、必要に応じてCodeReviewでさらにフィードバックを求めることができます。

私が適切な答えだと思うのは、次のスポイラー セクション内です。

(ここに defun クイーンを配置できます (行の列 n)
    「(行、列) がクイーンを配置できる場所である場合は t を返し、そうでない場合は nil を返します。」
    (ループ
       行の下の r
       c = (getqueencol rn) の場合
       決して (または (= col c)
                 (= (abs (- 行 r))
                    (abs (- col c))))))

于 2015-09-26T11:28:28.910 に答える