0

INVCNTの次のコードでNZECを取得します

; for lists of length > 2 inversions are the same as the number of elements
; against which the first is greater + the inversions of the remaining
(define (inversions l)
        (cond ((< (length l) 2) 0)
              (else (+ (length (filter (lambda (x) (> (car l) x)) (cdr l)))
                       (inversions (cdr l))))))

(use-modules (ice-9 rdelim))

(define (call-n-times proc n)
        (if (= 0 n)
            '()
            (cons (proc) (call-n-times proc (- n 1)))))

(define (solve)
        (write-line (inversions (call-n-times read (read)))))

(call-n-times solve (read))

ヒントはありますか?

4

1 に答える 1

0

非常に長いリストをフィルタリングすると、最大の再帰エラーが発生する可能性があります (仕様では最大 1000 万と言われています)。

(define (inversion L)
 (let loop ((accumulator 0) (L L))
   (if (null? L)
       accumulator
       (loop 
         (+ accumulator
            (fold
              (lambda (init next)
                (if (> (car l) next)
                    (+ init 1)
                    init))
              0
              (cdr L)))
         (cdr L)))))

第二に、これは読みやすくなりますが、そのフォールドを独自の関数に引き出します

(define (inversions-from-car L)
  (fold
     (lambda (init next)
        (if (> (car l) next)
            (+ init 1)
            init))
      0
      (cdr L)))

(define (inversion L)
 (let loop ((accumulator 0) (L L))
   (if (null? L)
       accumulator
       (loop 
         (+ accumulator
             (inversions-from-car L)     
         (cdr L)))))

書かれているように、n^2 の複雑さがあるため、これはデータ構造で遊ぶのに適した問題のように見えます。

n(log n) まで下げることができると思います

左側のノード数とペアになった値のリストにソートされたツリーを作成するとします。このセットの

'(2 3 8 6 1) -> '(1 2 3 6 8) -> 
(*tree (*entry 3 2 2)
       (*tree (*entry 2 1 1)
              (*tree (*entry 1 0 1)
                     ()
                     ())
              ())
        (*tree (*entry 8 1 1)
               (*tree (*entry 6 0 1)
                      ()
                      ())
               ()))      

*tree と *entry は type-tage です *tree には entry、left と right が必要です *entry には value、#left、number が必要です)

元のリストでアキュムレータがゼロの最初のものを見つけることから始めます

'(2 3 8 6 1)

Enrty の値が FIRST に一致する場合、アキュムレータに #left を追加します

値がエントリである場合は、アキュムレータを使用してツリーの左の枝で FIRST 再帰を実行します。

エントリの値が FIRST より小さい場合、アキュムレータに #left を追加して右の分岐を再帰します。

null ツリーの場合はエラーをスローします

次に、ツリーを更新する必要があります。

エントリの値が FIRST に等しい場合、エントリを変更して数値を 1 減らします

エントリの値が FIRST より大きい場合、エントリを変更して #left を 1 減らし、左の分岐で再帰します。

エントリの値が first より小さい場合、右の分岐で再帰します

null ツリーの場合はエラーをスローします

これらのルールを単一のトラバーサルに組み合わせることができます

さらに、#left が 0 で number が 0 の場合、右の分岐が null の場合はこのツリーを空のツリーに変更し、それ以外の場合は右の分岐を変更するというルールを追加します。

これはラフです(アイデアのテストされていないバージョン)

(define (rev-sorted-list->count-list L) ;;sort should be resverse of
                                        ;; final desired order
 (let loop ((value (car L)) (count 1) (L (cdr L)) (acc '()))
   (cond ((null? L) '())
         ((= value (car l))
          (loop value (+ 1 count) (cdr L) acc))
         (else 
          (loop (car l) 1 (cdr L) (cons (cons value count) acc))))))

(define (make-tree count c-L)
 (let* ((middle (ceiling (+ 1 count) 2))
        (left-count (- middle 1))
        (right-count (-count middle))
        (left (if (= 0 left-count)
                  null-tree 
                  (make-tree left-count c-L)))
        (entry+right
          (let loop ((index 1) (L c-L))
            (if (= index middle) 
                L
                (loop (+ 1 index) (cdr L)))))
        (entry 
         (make-entry 
           (caar entry+right)
           left-count
           (cdar entry+right))))
    (build-tree 
       entry
       left
       (if (= 0 right-count)
           null-tree
           (make-tree right-count (cdr entry+right))))))     

;;form left branches from starting points
;;;form right from stopping points
;;never mutating c-L or copies

;;if count = 0 then null tree

(define (build-tree entry left right)
  (list '*tree entry left right) 

(define (entry tree)
 (cadr tree)
(define (left-branch tree)
 (caddr tree))
(define (right-branch tree)
 (cadddr tree))

(define null-tree (list '*tree '()))
(define (null-tree? tree)
 (null? (entry tree)))

(define (make-entry value Nleft count)
 (let ((vec (make-vector 3)))
  (begin (vector-set! vec 0 value)
         (vector-set! vec 1 Nleft)
         (vector-set! vec 2 count)
         vec)))

;;might meessage passing function here

(define (entry-value entry)
 (vector-ref entry 0))

(define (entry-Nleft entry)
 (vector-ref entry 1))

(define (entry-Nleft-set! entry int)
 (vector-set! entry 1 int))

(define (entry-count entry)
 (vector-ref entry 2))

(define (entry-count-set! entry int)
 (vector-set! entry 2 int))

(define (inversions! Test-List Search-Tree)
 (let loop ((acc 0) (L Test-list) (T Search-tree))
   (cond ((null? L) acc)
         ((null-tree? T) (error "null tree " 
                                 "in inner loop of inversion!"))
         ((= (car L) (entry-value (entry T)))
          (entry-count-set! (entry T)
                            (- (entry-count (entry T)) 1))
          (if (and (= 0 (entry-count (entry T)))
                   (= 0 (entry-Nleft (entry T))))
               (set-cdr! T (right-branch T))
               'skip)
          (loop (+ acc (entry-Nleft (entry T)))
                (cdr L)
                Search-tree))
         ((< (car L) (entry-value (entry T)))
          (entry-Nleft-set! (entry T)
                            (- (entry-Nleft (entry T)) 1))
          (loop acc L (left-branch T)))
         ((> (car L) (entry-value (entry T)))
          (loop (+ acc (entry-Nleft (entry T)))
                L
                (right-branch T))))))
于 2014-01-25T19:37:31.080 に答える