有选择地谋杀正整数


21

介绍

算术监禁是一种特殊的工具,它可以包含正整数。但是,最近,正整数一直在试图逃脱。因此,管理人员已决定要消除一些正整数,以便向其他整数发送消息。他们聘请了一名软件工程师来编写程序,以找出要消除的整数以最大程度地发挥作用。

输入说明

输入是通过STDIN,命令行参数或用户输入函数(例如raw_input)给出的。您不能将其作为函数参数或预初始化的变量使用(例如,该程序希望在变量中输入x)。

输入的第一行包含一个正整数n,其中8 >= n >= 3。接下来是n包含n集合中字符的行[1,2,3,4,5,6,7,8,9]。这是一个示例输入:

5
22332
46351
65455
24463
65652

输出说明

监护人希望消除数字,以便满足以下条件:

  • 在结果网格的每一行和每一列中,没有数字将出现两次;
  • 消除的两个数字在水平或垂直方向上不得相邻;
  • 尚存数字必须形成正交的连续组-可以从任何尚存数字移动到仅在水平和垂直方向移动且永远不会越过任何被淘汰号码的任何其他尚存数字。

输出输入(减去第一行),将消除的数字替换为#

可能有不止一种解决方案。在这种情况下,您可以输出任何解决方案。

可能也没有解决方案。在这种情况下,输出字符串no answer

这是示例输入的可能输出:

#2#3#
46351
6#4#5
24#63
#56#2

输入和输出示例

每个输入都有多个输出,因此这些输出仅是示例。

输入:

5
46551
51565
32654
14423
43244

输出:

46#51
#156#
326#4
1#423
#324#

输入:

7
7183625
1681563
5238564
8786268
1545382
3814756
5325345

输出:

71#362#
#6815#3
5238#64
#7#62#8
154#382
3814756
#325#4#

输入:

8
21534768
75196287
68392184
96244853
44865912
76516647
89751326
43698979

输出:

21#34768
#5196287
683#21#4
9#24#853
#4865912
7#51#64#
89751326
436#8#7#

输入:

4
2222
2331
3112
1322

输出:

no answer

4
(也称为单身人士。)
门把手

这个难题非常好。谢谢。解决方案的工作
不是查尔斯(Charles)

1
我喜欢这个难题,但是无法在浏览器中使用JavaScript来按原样回答,因为唯一的用户输入法prompt不允许多行输入。
edc65

Answers:


0

Ruby,346 344 329 316字节,sl∞∞∞∞∞∞w

这是代码高尔夫球,不是代码快速,所以...

N=/!/=~G=$*[1..-1]*?!
M=N*N
g=->i{(!G[i]||G[i]<?*||i<0||A[i])&&break
A[i]=0
[1,N+1,-1,-1-N].map{|a|g[i+a]}}
f=->w,a{A=[];g[/\d/=~G=a];/#.{#{N}}?#/!~G&&/(\d)([^!]*|.{#{N}}.{#{O=N+1}}*)\1/!~G&&A.count(0)+w==M&&N.times.map{|m|puts G[m*(1+N),N]}&&exit
(w...M).map{|j|b=a+'';b[j]=?#
w<M&&f[w+1,b]}}
f[0,G]
$><<"no answer"

像这样使用它:

mad_gaksha@madlab ~/Applications/Tools $ ruby -W0 c50442.rb 3 323 312 231
#23
312
231

该标志-W0不是必需的,但是我建议您添加它以禁用警告或重定向stderr...

告诉我您是否有足够的耐心在n = 6,7,8的示例中运行它

变更日志

  • eachmap感谢@NotThatCharles
  • 检查相邻的删除和相同的数字两位regexp,类似于@NotThatCharles的建议
  • 优化阅读输入
  • 较小且较慢

尺寸的一些增量改进:\d[^#]倒数第二行短;M.times.to_a的长度大于(0..M-1).to_a
并非不是Charles

@NotThatCharles感谢您的提示!但是比;)M.times.to_a 1个字节也有效,并且长度相同。(0..M-1).to_a(0...M).to_a
blutorange

...很难计数
并不是说Charles

当n = 8时,它实际上完成了吗?
不是查尔斯(Charles)

@NotthatCharles如果足够长时间等待或使用超高速PC,是的。这是一个代码高尔夫球,对速度没有任何限制,因此我优先考虑了代码长度...
blutorange,2015年

5

红宝石-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).iComplex(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首字母


在lambda内部,break可以代替使用return,还可以节省一个字节。我真的很喜欢这个,很多技巧,而且速度更快。
blutorange 2015年

@blutorange谢谢!已应用。不过,仍然有办法达到344。
不是查尔斯(Charles)

更长一点,是的,但是否则看起来做得不错。我看到的另一件事:在第二行中,由于该变量a仅使用一次,因此可以进行设置J=gets(p).split*''。您是否尝试过cli参数,请参阅我的回答?
blutorange

3

HTML + JavaScript(ES6)459

使用HTML文本区域获取多行输入。

要进行测试,请在Firefox中运行该代码段。如果愿意,请扩大文本区域,将输入内容粘贴到文本区域内(请注意:确切的输入内容,每行都没有多余的空格),然后按Tab键即可。结果被附加。

方法:递归深度优先Serarch。它可以在几秒钟内找到所有测试用例的非最佳解决方案(这是哥德高尔夫,但对于常见的测试用例,有效答案终止)

<textarea onchange="s=this.value,
  z=s[0],o=-~z,k=[],X='no answer',f='#',
  (R=(s,t,h={},r=[],d=0)=>(
    s.map((v,i)=>v>0&&[i%o,~(i/o)].map(p=>h[p+=v]=[...h[p]||[],i])),
    [h[i][1]&&h[i].map(p=>r[d=p]=p)for(i in h)],
    d?r.some(p=>(
      (s[p+o]!=f&s[p-o]!=f&s[p-1]!=f&s[p+1]!=f)&&
      (
        g=[...s],g[p]=f,e=[...g],n=0,
        (F=p=>e[p]>0&&[1,-1,o,-o].map(d=>F(p+d),e[p]=--n))(p<o?p+o:p-o),
        t+n==0&&!k[g]&&(k[g]=1,R(g,t-1))
      )
    )):X=s.join('')
  ))([...s.slice(2)],z*z-1),this.value+=`

`+X"></textarea>

第一次尝试

方法:使用用户堆栈的非递归深度优先服务。
该功能可以在“广度优先搜索”中轻松转换为,l.pop切换到l.shift,因此使用队列而不是堆栈,但是它太慢了,我不确定无论如何它都能找到最佳解决方案。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.