最短ヌクレオチド連鎖問題

require 'bundler/setup'
require 'kaki/utils/nest_loop'

class Codon
  include Comparable
  
  def initialize(st)
    @cd = st
  end
  attr_reader :cd
  
  def <=>(a)
    x, y = @cd, a.cd
    l = r = 0 
    l = if x[1..2] == y[0..1]
      2
    elsif x[2] == y[0]
      1
    else
      0
    end
    r = if y[1..2] == x[0..1]
      2
    elsif y[2] == x[0]
      1
    else
      0
    end
    r - l
  end
  
  def inspect
    @cd
  end
  alias :to_s :inspect
end

def calc(x, y)
  if x.cd[1..2] == y.cd[0..1]
    2
  elsif x.cd[2] == y.cd[0]
    1
  else
    0
  end
end

a = [*0..3]
codon = [a, a, a].nest_loop {|x| x.join}.map {|x| Codon.new(x)}
max = 0

loop do
  c = codon.shuffle.sort
  20.times do
    co = 0
    c.each_cons(2) {|x, y| co += calc(x, y)}
    if max < co
      max = co
      puts 64 * 3 - max
      p c
    end
    c1 = c.sort
    break if c1 == c
    c = c1
  end
end

 
これまでの最小値。

105
[123, 231, 113, 132, 320, 200, 001, 120, 201, 010, 211, 100, 003, 033, 002, 023,
 013, 133, 333, 330, 303, 031, 313, 332, 102, 021, 101, 012, 223, 232, 203, 321,
 301, 331, 311, 112, 322, 220, 202, 212, 210, 230, 030, 300, 000, 020, 011, 111,
 110, 130, 302, 122, 032, 323, 233, 312, 022, 222, 221, 121, 213, 131, 310, 103]