代码之家  ›  专栏  ›  技术社区  ›  uckelman

如何计算两个大小字母的非幂de-Bruijn序列?

  •  13
  • uckelman  · 技术社区  · 16 年前

    我在计算 de Bruijn sequences 不 二次幂。

    对于具有2^k个字符的字母表,计算de Bruijn序列很容易:有几个简单的规则,例如 "Prefer Ones" and "Prefer Opposites" 它产生B(2,n)。B(2^k,n)与B(2,kn)完全相同,如果您将1和0读作字母表中实际字符的二进制代码。E、 例如,您可以将B(2,8n)解释为超过n个字节的长度序列。

    现在,我不知道如何将这些规则推广到两个大小的字母表的非幂。

    有一种通过图形计算de Bruijn序列的通用方法:让由字母表生成的每个n长度的序列都是一个节点;如果a的最右边的n-1字符与B的最左边的n-1字符相同,则将a到B的边放在一起。将每个边用字符串的最后一个字符标记在头顶点。任何 Eulerian path 通过这个图将生成一个de Bruijn序列,并且我们使用的特殊构造保证至少会有一个这样的路径。我们可以利用 Fleury's Algorithm 构造欧拉路径:

    1. 选择顶点。
    2. 通过某条边保留该顶点,然后删除该边,只选择其删除将使顶点与图形断开连接的边(如果没有其他选择)。
    3. 转到2直到所有边都消失。

    生成的字符串将是de Bruijn序列。

    5 回复  |  直到 16 年前
        1
  •  10
  •   smac89    10 年前

    这是我在C++中实现的算法,如图1所示 a paper by Sawada and Ruskey :

    void debruijn(unsigned int t,
                  unsigned int p,
                  const unsigned int k,
                  const unsigned int n,
                  unsigned int* a,
                  boost::function<void (unsigned int*,unsigned int*)> callback)
    {
      if (t > n) {
        // we want only necklaces, not pre-necklaces or Lyndon words
        if (n % p == 0) {
          callback(a+1, a+p+1);
        }
      }
      else {
        a[t] = a[t-p];
    
        debruijn(t+1, p, k, n, a, callback);
    
        for (unsigned int j = a[t-p]+1; j < k; ++j) {
          a[t] = j;
          debruijn(t+1, t, k, n, a, callback);
        }
      }
    }
    
    struct seq_printer {
      const std::vector<char>& _alpha;
    
      seq_printer(const std::vector<char>& alpha) : _alpha(alpha) {}
    
      void operator() (unsigned int* a, unsigned int* a_end) const {
        for (unsigned int* i = a; i < a_end; ++i) {
          std::cout << _alpha[*i];
        }
      }
    };
    
    ...
    
    std::vector<char> alpha;
    alpha.push_back('a');
    alpha.push_back('b');
    alpha.push_back('c');
    
    unsigned int* a = new unsigned int[N+1];
    a[0] = 0;
    
    debruijn(1, 1, alpha.size(), N, a, seq_printer(alpha));
    if (N > 1) std::cout << alpha[0];
    std::cout << std::endl;
    
    delete[] a;
    

    本文的全部参考文献是:Joe Sawada和Frank Ruskey,“一种生成固定密度项链的有效算法”,暹罗计算杂志 29个 :671-6841999年。

        2
  •  4
  •   Jonathan Dursi    16 年前

    this web page 在UVic的CS部门的组合组中,由于Fredericksen的原因,有一个结果,你可以通过将 Lyndon words 长度可被n整除。甚至还有源代码来构建您可以请求的序列。

        3
  •  3
  •   smac89    10 年前

    一年前 I translated that one 对鲁比说。

    # De Bruijn sequence
    # Original implementation by Frank Ruskey (1994)
    # translated to C by Joe Sawada
    # and further translated to Ruby by Jonas Elfström (2009)
    
    @n=4
    @k=10
    @a=[0]
    @sequence=[]
    
    def debruijn(t, p, alike)
      if t>@n
        if @n%p==0
          1.upto(p) {|j| @sequence<<@a[j]}
        end
      else
        @a[t]=@a[t-p]
        if @a[t]>0
          debruijn(t+1,p,alike+1)
        else
          debruijn(t+1,p,alike)
        end
        (@a[t-p]+1).upto(@k-1) {|j|
          @a[t]=j
          debruijn(t+1,t,alike+1)
        }
      end
    end
    
    debruijn(1,1,0)
    print @sequence.join
    

    alike 变量不起作用。下面生成相同的序列。

    @n=4
    @k=10
    @a=[0]
    @sequence=[]
    
    def debruijn(t, p)
      if t>@n
        if @n%p==0
          1.upto(p) {|j| @sequence<<@a[j]}
        end
      else
        @a[t]=@a[t-p]
        debruijn(t+1,p)
        (@a[t-p]+1).upto(@k-1) {|j|
          @a[t]=j
          debruijn(t+1,t)
        }
      end
    end
    
    debruijn(1,1)
    print @sequence.join
    
        4
  •  1
  •   smac89    10 年前

    或者您可以使用:

    def de_bruijn(k, n):
        a = [0] * k * n
        sequence = []
        def db(t, p):
            if t > n:
                if n % p == 0:
                    for j in range(1, p + 1):
                        sequence.append(a[j])
            else:
                a[t] = a[t - p]
                db(t + 1, p)
                for j in range(a[t - p] + 1, k):
                    a[t] = j
                    db(t + 1, t)
        db(1, 1)
        return sequence
    
    print de_bruijn(2,9)
    
        5
  •  0
  •   smac89    10 年前

    def debruijn(k, n):
        v = [0 for _ in range(n)]
        l = 1
        r = []
        while True:
            if n % l == 0:
                r.extend(v[0:l])
            for i in range(l, n):
                v[i] = v[i-l]
            l = n
            while l > 0 and v[l-1] >= k-1:
                l-=1
            if l == 0:
                break
            v[l-1] += 1
        return r
    
    print(debruijn(3,5))
    
        6
  •  0
  •   muggi    6 年前

    基于@stefan gruenwald的代码,它缺少 a simply categorizable set of words . 虽然我还不能修正它,但我写了几行来找出错误,这似乎是

    import itertools
    
    def debruijn (k, n) :
        v =  [ 0 for _ in range (n) ]
        l = 1
        r =  []
        while True :
            if n % l == 0 :
                r.extend (v [0:l])
            for i in range (l, n) :
                v [i] = v [i-l]
            l = n
            while l > 0 and v [l-1] >= k-1 :
                l -= 1
            if l == 0 :
                break
            v [l-1] += 1
        return r
    
    K = int (input ( 'k ' ) )
    N = int (input ( 'n ' ) )
    
    for k in range (K) :                                # length of alphabet
        for n in range (N) :                            # length of word(s)
            List = debruijn (k, n)
            l = ''
            for L in List :
                l += str (L)
            L = itertools.product (range (k), repeat = n)
            print ( 'alphabet k', k, '\tword n', n, str ('|' + l + '|') )
            for a in L :
                searchstr = ''
                for A in a :
                    searchstr += str (A)
                if not searchstr in l :
                    print ( searchstr, end = ' ' )
            print ()
    

    也可保存在文件中:

    import itertools
    
    def debruijn (k, n) :
        v =  [ 0 for _ in range (n) ]
        l = 1
        r =  []
        while True :
            if n % l == 0 :
                r.extend (v [0:l])
            for i in range (l, n) :
                v [i] = v [i-l]
            l = n
            while l > 0 and v [l-1] >= k-1 :
                l -= 1
            if l == 0 :
                break
            v [l-1] += 1
        return r
    
    K = int (input ( 'k ' ) )
    N = int (input ( 'n ' ) )
    
    for k in range (K) :                                # length of alphabet
        for n in range (N) :                            # length of word(s)
            List = debruijn (k, n)
            l = ''
            for L in List :
                l += str (L)
            L = itertools.product (range (k), repeat = n)
            with open (str (k) + '-' + str (n), 'w') as f :
                f.write ( 'alphabet length ' + str (k) + '\tword length ' + str (n) + '\n' + l + '\nnot in:\n' )
                for a in L :
                    searchstr = ''
                    for A in a :
                        searchstr += str (A)
                    if not searchstr in l :
                        f.write ( searchstr + ' ' )