선택적으로 양의 정수를 살해


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

답변:


0

루비 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가 제안한 것과 유사하게 인접한 삭제 및 동일한 숫자를 두 s로 확인하십시오.
  • 최적화 된 판독 입력
  • 작고 느림

몇 가지 점진적인 크기 개선 : 두 번째 줄 \d보다 짧습니다 [^#]. M.times.to_a이상이(0..M-1).to_a
Charles

@NotThatCharles 팁 주셔서 감사합니다! 그러나 ;) 보다 M.times.to_a1 바이트 짧아도 작동하며 길이는 같습니다. (0..M-1).to_a(0...M).to_a
blutorange

... 카운팅은 어렵다
Charles가 아닙니다.

n = 8 일 때 실제로 완료됩니까?
찰스

@NotthatCharles 만약 당신이 충분히 기다리거나 초고속 PC를 사용한다면, 그렇습니다. 이것은 속도에 대한 제한이없는 코드 골프입니다. 그래서 나는 코드 길이를 우선시했습니다 ...
blutorange

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).i훨씬 짧다Complex(y%N,y/N)

또한 문자열을 생성하기위한 두 개의 복잡한 조건이있는 [cond1?str1a:str1b,cond2?str2a:str2b]*''경우 모든 parens 또는 #{}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 점진적 개선-esp.find아니select

475 개 떨어짐u 가 줄 / 콜 듀프 빌더를

503 은 한 번에 한 행 / 열당 하나의 중복 숫자 만 해결합니다.

530 사용map &:pop대신values

531 듀피 배열을 만드는 람다를 당겨

552 개 죄송합니다! 요구 사항을 놓쳤다

536 약간 개선 된 듀스 어레이 인구 (이전의 수치 d)

541 초기


내부 람다 break대신을 (를 return) 사용 하면 1 바이트를 더 절약 할 수 있습니다 . 나는 정말로 이것, 많은 트릭과 훨씬 더 빠릅니다.
blutorange

@blutorange 감사합니다! 적용된. 그래도 344를 치는 방법은 여전히 ​​있습니다.
찰스

조금 더 그렇습니다.하지만 그렇지 않으면 잘 보입니다. 내가 한 번 더 보았습니다 : 두 번째 줄에서 변수 a가 한 번만 사용되므로 만들 수 J=gets(p).split*''있습니다. cli arguments를 사용해 보셨습니까? 내 대답을 참조하십시오.
blutorange

3

HTML + 자바 스크립트 ( ES6 ) 459

여러 줄 입력을 얻기 위해 HTML 텍스트 영역을 사용합니다.

테스트하려면 Firefox에서 스 니펫을 실행하십시오. 원하는 경우 텍스트 영역을 확대하고 텍스트 영역 내부에 입력을 붙여넣고 (정확한 입력, 줄에 추가 공백 없음) 탭을 두십시오. 결과가 추가됩니다.

방법 : 재귀 깊이 첫 번째 군주. 몇 초 만에 모든 테스트 사례에 대해 최적이 아닌 솔루션을 찾습니다 (gode golf이지만 일반적인 테스트 사례 에서는 유효한 답변 종료 되어야 함 ).

<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.popl.shift너무 큐 대신 스택을 사용하여,하지만 너무 느린 나는 확실히 어쨌든 최적의 솔루션을 찾을 수 있습니다 아니에요.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.