在Scheme中生成项链的好的简单算法?

在Scheme中生成项链的好的简单算法?,scheme,combinatorics,necklaces,Scheme,Combinatorics,Necklaces,长度为n的k元项链是一个长度为n的有序列表,其项目从长度为k的字母表中提取,该字母表是共享旋转顺序的所有列表中的第一个字母表 例如: (1 2 3)和(1 3 2)是字母表{1 2 3}中长度为3的项链 更多信息: 我想在Scheme(或您选择的Lisp)中生成这些。我找到了一些文件… Savage-生成项链的新算法 Sawada-在固定摊销时间内生产手镯 Sawada-生成带有禁用子串的项链 …但其中的代码对我来说是不透明的。主要是因为它们似乎既没有传递字母表,也没有传递所需的长度(n)。我

长度为n的k元项链是一个长度为n的有序列表,其项目从长度为k的字母表中提取,该字母表是共享旋转顺序的所有列表中的第一个字母表

例如: (1 2 3)和(1 3 2)是字母表{1 2 3}中长度为3的项链

更多信息:

我想在Scheme(或您选择的Lisp)中生成这些。我找到了一些文件…
Savage-生成项链的新算法
Sawada-在固定摊销时间内生产手镯
Sawada-生成带有禁用子串的项链
…但其中的代码对我来说是不透明的。主要是因为它们似乎既没有传递字母表,也没有传递所需的长度(n)。我正在寻找的方案程序的形式是(necklaces n’(a b c…)

通过首先生成k^n列表,然后过滤掉旋转,我可以很容易地生成这些。但是它的内存效率非常低


谢谢

我将执行两步流程。首先,从字母表中找出n个元素的每个组合。然后,对于每个组合,选择最低的值,并生成剩余项的所有排列

编辑:这里有一些代码。它假定输入列表已经排序,并且不包含重复项

(define (choose n l)
  (let ((len (length l)))
    (cond ((= n 0) '(()))
          ((> n len) '())
          ((= n len) (list l))
          (else (append (map (lambda (x) (cons (car l) x))
                             (choose (- n 1) (cdr l)))
                        (choose n (cdr l)))))))

(define (filter pred l)
  (cond ((null? l) '())
        ((pred (car l)) (cons (car l) (filter pred (cdr l))))
        (else (filter pred (cdr l)))))

(define (permute l)
  (cond ((null? l) '(()))
        (else (apply append 
                     (map (lambda (x)
                             (let ((rest (filter (lambda (y) (not (= x y))) l)))
                               (map (lambda (subperm) (cons x subperm))
                                    (permute rest))))
                      l)))))

(define (necklaces n l)
  (apply
   append
   (map
    (lambda (combination)
      (map (lambda (permutation)
              (cons (car combination) permutation))
           (permute (cdr combination))))
    (choose n l))))


(display (choose 1 '(1 2 3 4 5))) (newline)
(display (choose 2 '(1 2 3 4 5))) (newline)
(display (permute '(1 2))) (newline)
(display (permute '(1 2 3))) (newline)
(display (necklaces 3 '(1 2 3 4))) (newline)
(display (necklaces 2 '(1 2 3 4))) (newline)
例如:(1 2 3)和(1 3 2)是字母表{1 2 3}中长度为3的项链

你忘了(11)(12)(13)(12)(13)(23)(22)(23)(23)(33)。项链可以包含重复项

(define (choose n l)
  (let ((len (length l)))
    (cond ((= n 0) '(()))
          ((> n len) '())
          ((= n len) (list l))
          (else (append (map (lambda (x) (cons (car l) x))
                             (choose (- n 1) (cdr l)))
                        (choose n (cdr l)))))))

(define (filter pred l)
  (cond ((null? l) '())
        ((pred (car l)) (cons (car l) (filter pred (cdr l))))
        (else (filter pred (cdr l)))))

(define (permute l)
  (cond ((null? l) '(()))
        (else (apply append 
                     (map (lambda (x)
                             (let ((rest (filter (lambda (y) (not (= x y))) l)))
                               (map (lambda (subperm) (cons x subperm))
                                    (permute rest))))
                      l)))))

(define (necklaces n l)
  (apply
   append
   (map
    (lambda (combination)
      (map (lambda (permutation)
              (cons (car combination) permutation))
           (permute (cdr combination))))
    (choose n l))))


(display (choose 1 '(1 2 3 4 5))) (newline)
(display (choose 2 '(1 2 3 4 5))) (newline)
(display (permute '(1 2))) (newline)
(display (permute '(1 2 3))) (newline)
(display (necklaces 3 '(1 2 3 4))) (newline)
(display (necklaces 2 '(1 2 3 4))) (newline)
如果你只是在寻找长度为N的项链,从大小为N的字母表中提取,不包含重复项,那么很容易:会有(N-1)!项链,每条项链的形式为
(1::perm)
,其中
perm
是{2..N}的任何排列。例如,{1..4}的项链是(1234)(1243)(1234)(12342)(1432)(14323)(1432)(143)(1432)。扩展此方法以处理长度K
但是如果你想找到真正的项链,它可能包含重复的元素,那么它就不是那么简单。

用于生成项链的FKM算法。PLT计划。表演没那么火爆。它将把任何东西作为字母表,并将内部数字映射到您提供的任何东西上。似乎是正确的;没有保证。我在翻译循环时很懒,所以你得到了for循环和escape连续体的奇怪组合

(require srfi/43)

(define (gennecklaces n alphabet)
  (let* ([necklaces '()]
         [alphavec (list->vector alphabet)]
         [convert-necklace
          (lambda (vec)
            (map (lambda (x) (vector-ref alphavec x)) (cdr (vector->list vec))))]
         [helper
          (lambda (n k)
            (let ([a (make-vector (+ n 1) 0)]
                  [i n])
              (set! necklaces (cons (convert-necklace a) necklaces))
              (let/ec done
                (for ([X (in-naturals)])
                  (vector-set! a i (add1 (vector-ref a i)))
                  (for ([j (in-range 1 (add1 (- n i)))])
                    (vector-set! a (+ j i)
                                 (vector-ref a j)))
                  (when (= 0 (modulo n i))
                    (set! necklaces (cons (convert-necklace a) necklaces)))
                  (set! i n)
                  (let/ec done
                    (for ([X (in-naturals)])
                      (unless (= (vector-ref a i)
                                 (- k 1))
                        (done))
                      (set! i (- i 1))))
                  (when (= i 0)
                    (done))))))])
    (helper n (length alphabet))
    necklaces))

作为第一个想法,你可以做一些明显但效率低下的事情:逐步检查所有的组合,检查它们是否是项链,也就是说,它们是否是元素在词汇上最小的旋转(在上面的文章中,第5页的正式定义)。这与您建议的方式类似,但您会在生成所有非项链后立即将其丢弃

除此之外,我认为您必须理解本文():

T.Wang和C.Savage,“生成项链的新算法”,报告 TR-90-20,北卡罗来纳州立大学计算机科学系 (1990年)


这并不太难,你可以通过实现所描述的
tau
sigma
函数,然后按照本文概述的顺序应用它们来分解它。

列出的10个项链中只有两个是简单的省略,还是你想要项链以外的东西?