知耻而后勇,自己琢磨的排列组合生成算法

之前写了一个排列组合生成算法,主要思路是补集,然而实际上算补集太麻烦而且消耗时间太多。后面写概率模拟的时候下定决心重新写了一遍,结果效率还挺好。我只是一名菜鸟,很多博客关于排列组合算法的科普其实我看得不太懂,我也不知道下面这个的思路是怎样的(忘记了……)

 

# 使用哈希去重

def permlist_iter(n, m, &pr)
  # 求递增的排列数组
  list = (1..m).to_a
  info = {}
  (1..m).each do |x|
    info[x] = true
  end
  ((m+1)..n).each do |x|
    info[x] = nil
  end
  pos = 1
  loop do
    pr.call(list, pos)
    pos += 1
    # 修改排列数组
    i = m-1
    #~ puts "info=#{info}"
    while (i>=1)
      k = list[i]+1
      while (k<=n)
        if info[k]==nil
          info[list[i]] = nil
          info[k] = true
          list[i] = k
          break
        end
        k += 1
      end
      if (k<=n)
      #~ # 修改右边
        last = 1
        ((i+1)..(m-1)).each do |j|
          (last..n).each do |k|
            if (info[k]==nil)
              info[k] = true
              list[j] = k
              last = k+1
              break
            end
          end
        end
        break
      end
      
      info[list[i]] = nil
      i -= 1  
    end
    if (i==0)
      break if list[0]==n
      info[list[0]] = nil
      info[list[0]+1] = true
      list[0] += 1
      last = 1
      (1..(m-1)).each do |j|
        (last..n).each do |k|
          if (info[k]==nil)
            info[k] = true
            list[j] = k
            last = k+1
            break
          end
        end
      end
    end
  end
  return
end

def comblist_iter(n, m, &pr)
  # 求递增的组合数组
  list = (1..m).to_a
  info = {}
  (1..m).each do |x|
    info[x] = true
  end
  ((m+1)..n).each do |x|
    info[x] = nil
  end
  pos = 1
  loop do
    pr.call(list, pos)
    pos += 1
    # 修改组合数组
    i = m-1
    #~ puts "info=#{info}"
    while (i>=1)
      k = list[i]+1
      while (k<=n)
        if info[k]==nil
          info[list[i]] = nil
          info[k] = true
          list[i] = k
          break
        end
        k += 1
      end
      if (k<=n)
      #~ 修改右边
        ((i+1)..(m-1)).each do |j|
          info[list[j]] = nil
        end
        last = k+1
        ((i+1)..(m-1)).each do |j|
          (last..n).each do |k|
            if (info[k]==nil)
              info[k] = true
              list[j] = k
              last = k+1
              break
            end
          end
        end
        break
      end
      
      #~ info[list[i]] = nil
      i -= 1  
    end
    if (i==0)
      break if list[0]==(n-m+1)
      list.each do |x|
        info[x] = nil
      end
      info[list[0]+1] = true
      list[0] += 1
      last = list[0]+1
      (1..(m-1)).each do |j|
        (last..n).each do |k|
          if (info[k]==nil)
            info[k] = true
            list[j] = k
            last = k+1
            break
          end
        end
      end
    end
  end
  return
end

=begin
# 测试排列数组
count = 0
tn1 = Time.now
permlist_iter(13, 8) do |list, pos|
  #puts "(#{pos})=>#{list}"
  #~ gets
  count += 1
end
puts "time:#{Time.now-tn1}", count
=end
#~ =begin
# 测试组合数组
count = 0
tn1 = Time.now
comblist_iter(25, 14) do |list, pos|
  #~ puts "(#{pos})=>#{list}"
  #~ gets
  count += 1
end
puts "time:#{Time.now-tn1}", count
#=end

 

posted @ 2020-08-15 16:24  uu2crain  阅读(191)  评论(0)    收藏  举报