红宝石-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]*''
比添加所有paren或#{}
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
并压紧行/ col dupe生成器
503一次只能解决每行/列一个重复的数字。
530使用map &:pop
的,而不是values
531拉出使dupes排列的lambda
552 oops!错过了要求
536个骗子阵列的人口略有改善(以前是d
)
541首字母