Рубі - 541 ..., 394
Основний алгоритм - це рекурсивний пошук глибоко-перших дублікатів для підтвердження вибору, переглядаючи рядок 1, потім стовпець 1, потім рядок 2 тощо і перевіряючи, чи не загинули два сусіди та чи підключена сітка (це break if
пункт у там, і шматочок, який приходить перед цим).
K=(0...(N=gets.to_i)*N).to_a
J=gets(p).split*''
H=->m{K&[m+1,m-1,m+N,m-N]}
Q=->k{s=[k[j=0]]
(j=s.size
s.map{|x|(s+=H[x]&k).uniq!})while s[j]
break if(K-k).any?{|m|(H[m]-k)[0]}||k!=k&s
$><<K.map{|m|[k.index(m)?J[m]:?#,m%N>N-2?"
":p]}*''|exit if !g=((0...N*2).map{|x|(k.select{|m|m.divmod(N)[x/N]==x%N}.group_by{|m|J[m]}.find{|l,c|c[1]}||[])[1]}-[p]).min
g.map{|d|Q[k-g<<d]}}
Q[K]
puts"no answer"
Деякі акуратні хитрощі:
if w[1]
набагато коротше, ніж, if !w.one?
і якщо ви знаєте, що принаймні один член, це такий же результат.
Так само [0]
коротше, ніж any?
якщо немає блоку, і s[j]
це милий ярлик j<s.size
(технічно це більше схоже j.abs<s.size
)
І y%N+(y/N).i
набагато коротше, ніжComplex(y%N,y/N)
Крім того, коли для створення рядків є два складних умови, це може бути коротше, [cond1?str1a:str1b,cond2?str2a:str2b]*''
ніж додати всі паролі або #{}
s.
Розколювання та пояснення:
(Це з версії 531 байт. Я вніс зміни. Найбільш помітно, я з того часу усунув виклик до продукту - просто вирішуйте одну цифру на рядок / стовпець за один раз, і J тепер просто масив, індексований цілі числа. Усі координати - це цілі числа.)
H
обчислює сусідів
def H m
# m, like all indices, is a complex number
# where the real part is x and the imaginary is y
# so neighbors are just +/-i and +/-1
i='i'.to_c
neighborhood = [m+1, m-1, m+i, m-i]
# and let's just make sure to eliminate out-of-bounds cells
K & neighborhood
end
N
- розмір сітки
N = gets.to_i
K
- це ключі до карти (складні номери)
# pretty self-explanatory
# a range of, e.g., if N=3, (0..8)
# mapped to (0+0i),(1+0i),(2+0i),(0+1i),(1+1i),(2+1i),...
K = (0..N**2-1).map{|y| (y%N) +(y/N).i }
J
карта вводу (в'язниця)
# so J is [[0+0,"2"],[0+1i,"3"],....].to_h
J=K.zip($<.flat_map {|s|
# take each input line, and...
# remove the "\n" and then turn it into an array of chars
s.chomp.chars
}).to_h
k
- це ключі, що не вбиваються
# starts as K
Q
є основним рекурсивним методом
def Q k
j=0 # j is the size of mass
# the connected mass starts arbitrarily wherever k starts
mass=[k[0]]
while j < s.size # while s hasn't grown
j = mass.size
mass.each{|cell|
# add all neighbors that are in k
(mass+=H[cell] & k).uniq!
}
end
# if mass != k, it's not all orthogonally connected
is_all_connected = k!=k&mass
# (K-k) are the killed cells
two_neighbors_killed = (K-k).any?{|m|
# if any neighbors of killed cells aren't in k,
# it means it was killed, too
(H[m]-k)[0]
}
# fail fast
return if two_neighbors_killed || is_all_connected
def u x
x.group_by{|m|J[m]}.select{|l,c|c[1]}
end
rows_with_dupes = Array.new(N){|r|u[k.select{|m|m.imag==r}]}
cols_with_dupes = Array.new(N){|r|u[k.select{|m|m.real==r}]}
# dupes is an array of hashes
# each hash represents one row or column. E.g.,
# {
# "3"=>[(0+0i),(1+0i),(3+0i)],
# "2"=>[(2+0i),(4+0i)]
# }
# means that the 0th, 1st and 3rd cells in row 0
# all are "3", and 2nd and 4th are "2".
# Any digits without a duplicate are rejected.
# Any row/col without any dupes is removed here.
dupes = (rows_with_dupes+cols_with_dupes-[{}])
# we solve one row at a time
first_row = dupes[0]
if !first_row
# no dupes => success!
J.map{|m,v|k.member?(m)?v:?#}.each_slice(N){|s|puts s*''}
exit
else
# the digit doesn't really matter
t=first_row.values
# cross-multiply all arrays in the row to get a
# small search space. We choose one cell from each
# digit grouping and drop the rest.
t.inject(:product).map{ |*e|
# Technically, we drop all cells, and add back the
# chosen cells, but it's all the same.
new_k = k-t.flatten+e.flatten
# and then search that space, recursively
Q[new_k]
}
end
end
Код виконується за допомогою:
# run with whole board
Q[K]
# if we get here, we didn't hit an exit, so we fail
puts"no answer"
Журнал змін
394 додав пропозицію @ blutorange нижче, і вирізав набагато більше маніпуляцій
408 ще раз переглянули вихід. Також використовуйте .min
замість того, що .inject(:+)
я все одно беру один рядок.
417 коротший розрахунок випуску
421 знизили складні числа. Просто використовуйте цілі числа. Збережіть пакет
Ще 450 поліпшень введення
456 поліпшень введення
462 поступових поліпшень - особливо find
, неselect
475 скинув u
і розчавив будівельник дуп
503 вирішувати одночасно одну копію цифр на рядок / стовпець.
530 використання map &:pop
замістьvalues
531 витягніть лямбда, що складає матовий масив
552 ой! пропустили вимогу
536 незначно поліпшена популяція мальпових масивів (що раніше d
)
541 початковий