영국 정보국을 이길 수 있습니까? (노노 그램 솔버)


20

이제 영국 정보국을 무 찌르기 위해 위험한 퀘스트를 시작할 때입니다. 이 과제의 목표는 노노 그램을 해결하는 가장 짧은 코드를 작성하는 것입니다.

노노 그램이란 무엇입니까?

노노 그램 퍼즐

규칙은 간단합니다. 정사각형 격자가 있으며 검은 색으로 채워지거나 비워 두어야합니다. 그리드의 각 행 옆에는 해당 행의 검은 색 사각형의 길이가 나열됩니다. 각 열 위에는 해당 열에있는 검은 사각형의 길이가 나열됩니다. 당신의 목표는 모든 검은 사각형을 찾는 것입니다. 이 퍼즐 유형에서 숫자는 이산 단층 촬영의 한 형태로, 주어진 행이나 열에 채워진 사각형의 끊어지지 않은 선의 수를 측정합니다. 예를 들어, "4 8 3"의 단서는 연속 된 그룹 사이에 하나 이상의 공백 사각형이있는 순서대로 4, 8 및 3 개의 채워진 사각형 세트가 있음을 의미합니다. [ 1 ] [ 2 ]

위의 Nonogram에 대한 해결책은 다음과 같습니다.

노노 그램 해결

구현 세부 사항

그러나 비노 그램을 나타내도록 선택할 수 있지만 원하는 언어로 입력하십시오. 출력도 마찬가지입니다. 이 과제의 목표는 문자 그대로 작업을 완료하는 것입니다. 프로그램이 제공하는 출력으로 노노 그램을 해결할 수 있다면 유효합니다. 한 가지주의 사항은 온라인 솔버를 사용할 수 없다는 것입니다. :)

이 문제는 완전히 효율적인 해결책이 없다는 점에서 알고리즘 적으로 매우 까다 롭습니다 (np 완료). 따라서 더 큰 해결책을 해결할 수 없다는 처벌을받지 못합니다. 큰 경우를 처리 할 수 ​​있습니다 (보너스 참조). 벤치 마크로 내 솔루션은 5-10 초 내에 최대 25x25까지 작동합니다. 여러 언어 중에서 융통성을 허용하려면 25x25 노노 그램에 5 분 미만의 솔루션이 충분합니다.

퍼즐은 항상 정사각형 NxN 노노 그램으로 가정 할 수 있습니다.

당신이 사용할 수있는 솔루션을 테스트하기 위해 온라인 노노 그램 퍼즐 메이커.

채점

물론 원하는 언어를 자유롭게 사용할 수 있으며 코드 골프이기 때문에 항목이 순서대로 정렬됩니다. accuracy -> length of code -> speed.그러나 코드 골프 언어로 낙심하지 마십시오. 골프를 시도하는 모든 언어의 대답 흥미로운 방식으로 공감 될 것입니다!

보너스

실제로 영국의 지능에 의해 발표 암호화 크리스마스 카드에서 Nonograms에 대해 배웠 여기 . 첫 번째 부분은 기본적으로 거대한 25x25 Nonogram이었습니다. 당신의 솔루션이 이것을 해결할 수 있다면, 당신은 kudos를 얻을 것입니다 :)

데이터 입력 측면에서 귀하의 삶을 편하게하기 위해 무료로 사용할 수있는이 특정 퍼즐의 데이터를 어떻게 표현했는지 알려 드리겠습니다. 처음 25 줄은 행 단서, '-'구분자 라인, 25 개의 줄 단서, '#'구분자 라인, 사각형 단서가 채워진 그리드 표현입니다.

7 3 1 1 7
1 1 2 2 1 1
1 3 1 3 1 1 3 1
1 3 1 1 6 1 3 1
1 3 1 5 2 1 3 1
1 1 2 1 1
7 1 1 1 1 1 7
3 3
1 2 3 1 1 3 1 1 2
1 1 3 2 1 1
4 1 4 2 1 2
1 1 1 1 1 4 1 3
2 1 1 1 2 5
3 2 2 6 3 1
1 9 1 1 2 1
2 1 2 2 3 1
3 1 1 1 1 5 1
1 2 2 5
7 1 2 1 1 1 3
1 1 2 1 2 2 1
1 3 1 4 5 1
1 3 1 3 10 2
1 3 1 1 6 6
1 1 2 1 1 2
7 2 1 2 5
-
7 2 1 1 7
1 1 2 2 1 1
1 3 1 3 1 3 1 3 1
1 3 1 1 5 1 3 1
1 3 1 1 4 1 3 1
1 1 1 2 1 1
7 1 1 1 1 1 7
1 1 3
2 1 2 1 8 2 1
2 2 1 2 1 1 1 2
1 7 3 2 1
1 2 3 1 1 1 1 1
4 1 1 2 6
3 3 1 1 1 3 1
1 2 5 2 2
2 2 1 1 1 1 1 2 1
1 3 3 2 1 8 1
6 2 1
7 1 4 1 1 3
1 1 1 1 4
1 3 1 3 7 1
1 3 1 1 1 2 1 1 4
1 3 1 4 3 3
1 1 2 2 2 6 1
7 1 3 2 1 1
#
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 1 1 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 1 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 1 1 0 0 1 0 0 0 1 1 0 0 1 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 1 1 0 0 0 0 1 1 0 0 0 0 1 0 0 0 0 1 1 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

그리고 여기 귀하의 편의를 위해 약간 다른 버전이 있습니다. 각 요소가 목록의 목록 인 쉼표로 구분 된 튜플 (행, 열)

([[7, 3, 1, 1, 7],
  [1, 1, 2, 2, 1, 1],
  [1, 3, 1, 3, 1, 1, 3, 1],
  [1, 3, 1, 1, 6, 1, 3, 1],
  [1, 3, 1, 5, 2, 1, 3, 1],
  [1, 1, 2, 1, 1],
  [7, 1, 1, 1, 1, 1, 7],
  [3, 3],
  [1, 2, 3, 1, 1, 3, 1, 1, 2],
  [1, 1, 3, 2, 1, 1],
  [4, 1, 4, 2, 1, 2],
  [1, 1, 1, 1, 1, 4, 1, 3],
  [2, 1, 1, 1, 2, 5],
  [3, 2, 2, 6, 3, 1],
  [1, 9, 1, 1, 2, 1],
  [2, 1, 2, 2, 3, 1],
  [3, 1, 1, 1, 1, 5, 1],
  [1, 2, 2, 5],
  [7, 1, 2, 1, 1, 1, 3],
  [1, 1, 2, 1, 2, 2, 1],
  [1, 3, 1, 4, 5, 1],
  [1, 3, 1, 3, 10, 2],
  [1, 3, 1, 1, 6, 6],
  [1, 1, 2, 1, 1, 2],
  [7, 2, 1, 2, 5]],
 [[7, 2, 1, 1, 7],
  [1, 1, 2, 2, 1, 1],
  [1, 3, 1, 3, 1, 3, 1, 3, 1],
  [1, 3, 1, 1, 5, 1, 3, 1],
  [1, 3, 1, 1, 4, 1, 3, 1],
  [1, 1, 1, 2, 1, 1],
  [7, 1, 1, 1, 1, 1, 7],
  [1, 1, 3],
  [2, 1, 2, 1, 8, 2, 1],
  [2, 2, 1, 2, 1, 1, 1, 2],
  [1, 7, 3, 2, 1],
  [1, 2, 3, 1, 1, 1, 1, 1],
  [4, 1, 1, 2, 6],
  [3, 3, 1, 1, 1, 3, 1],
  [1, 2, 5, 2, 2],
  [2, 2, 1, 1, 1, 1, 1, 2, 1],
  [1, 3, 3, 2, 1, 8, 1],
  [6, 2, 1],
  [7, 1, 4, 1, 1, 3],
  [1, 1, 1, 1, 4],
  [1, 3, 1, 3, 7, 1],
  [1, 3, 1, 1, 1, 2, 1, 1, 4],
  [1, 3, 1, 4, 3, 3],
  [1, 1, 2, 2, 2, 6, 1],
  [7, 1, 3, 2, 1, 1]])

슬프게도 내 웹 사이트가 다운되었지만 꽤 빠른 Nonogram 솔버를 사용했습니다. 5-10 분이 과도하게 들립니다.
Neil


1
@dwana 당신은 해결할 수없는 경우에 대해 걱정할 필요가 없습니다. 무작위 응답의 경우 25x25 노노 그램에서 2 ^ 625 개의 구성이 가능합니다. 문맥 상, 이것은 알려진 우주의 원자 수의 두 배 이상입니다 (즉, 우주의 각 원자를 조금씩 사용한 경우에는 가능성을 저장할 공간이 충분하지 않습니다). 시간의 관점에서, 각 구성의 유효성을 확인하는 데 나노 초 (풍부한 시간)가 걸린다면 코드 실행이 완료되는 데 7 평생의 우주가 필요합니다 :)
gowrath

1
해결할 수없는 경우를 명확히하기위한 Ty. (+ 나는 ~ 2.1546362E-186 초 안에 답을 확인하는 마법의 PC를 가지고있다)
dwana

1
CSV에는 사각형 힌트가 없습니다. 다음은 JS를 생성하는 것입니다.s=[].fill([].fill(0,0,25),0,25);s[3][3]=s[3][4]=s3[3][12]=s3[3][13]=s3[3][21]=s[8][6]=s[8][7]=s[8][10]=s[8][14]=s[8][15]=s[8][18]=s[16][6]=s[16][11]=s[16][16]=s[16][20]=s[21][3]=s[21][4]=s[21][9]=s[21][10]=s[21][15]=s[21][20]=s[21][21]=1;
Titus

답변:


5

Brachylog , 70 69 바이트

[R:C]hlL~l:L:1f=.:3aR,.z:3aC,
tL,?he##ElL,E:2a
.<2,_1<
@b:4f:la
e.h1,

여기에는 두 개의 목록이 있습니다 (먼저 행 표시기, 열 표시기). 각 지표는 그 자체가 목록입니다 ( [3,1]한 행 과 같은 상황 에 대한 것).

이 버전은 챌린지의 5 x 5 예제를 해결하는 데 약 3 분이 걸립니다.

훨씬 효율적인 버전, 91 바이트

[R:C]hlL~l:L:1f:Cz:3az:Rz:3a=.:4aR,.z:4aC,
tL,?he##ElL,E:2a
.<2,_1<
:+a#=,?h
@b:5f:la
e.h1,

온라인으로 사용해보십시오!

이것은 완전한 무차별 대 입력이 아닙니다. 유일한 차이점은 각 행과 열의 1의 숫자가 입력의 지표로 주어진 숫자와 일치하도록 셀 값에 제약 조건을 부과한다는 것입니다. 그런 다음 유일한 무력 부분은 1의 "블록"이 표시로 주어진 것과 일치하는 제약 조건을 가진 그리드를 찾는 것입니다.

이것은 도전의 5x5 예제에서 약 0.05 초가 걸립니다. 제약 조건 측면에서 하나 이상의 0으로 구분 된 블록을 표현하는 방법을 알지 못하기 때문에 보너스 경우에는 여전히 너무 느립니다.

설명

93 바이트 이하 버전에 대해 설명하겠습니다. 이 둘의 유일한 차이점은 70 바이트 버전에는 존재하지 않는 술어 3에 대한 호출과 술어의 번호 매기기입니다 (하나가 적으므로).

  • 주요 술어 :

    [R:C]     Input = [R, C]
    hlL       The length of R is L
    ~l        Create a list of length L
    :L:1f     Each element of that list is a sublist of length L with cells 0 or 1 (Pred 1)
              %%% Part unique to the 93 bytes version
    :Cz       Zip the rows of the list of lists with C
    :3a       The sum of 1s in each row is equal to the sum of the indicators (Pred 3)
    z         Transpose
    :Rz       Zip the columns of the list of lists with R
    :3a       The sum of 1s in each column is equal to the sum of the indicators (Pred 3)
              %%%
    =.        Assign values to the cells of the list of lists which satisfy the constraints
    :4aR,     The blocks of 1s must match the indicators on rows
    .z        Transpose
    :4aC,     The blocks of 1s must match the indicators on columns
    
  • 술어 1 : 행이 특정 길이를 갖도록하고 각 셀이 0 또는 1이되도록합니다.

    tL,       L is the length given as second element of the input
    ?he       Take an element from the list
    ##ElL,    That element E is itself a list of length L
    E:2a      The elements of E are 0s and 1s (Pred 2)
    
  • 술어 2 : 변수를 0 또는 1로 제한

    .<2,      Input = Output < 2
    _1<       Output > -1
    
  • 술어 3 : 목록의 1의 합계는 지표의 합계와 같아야합니다 (예 : 지표가 [3 : 1]이면 목록의 합계는 4 여야 함)

    :+a       Sum the elements of the list and sum the indicator
    #=,       Both sums must be equal
    ?h        Output is the list
    
  • 술어 4 : 1의 블록이 표시기와 일치하는지 확인

    @b        Split the list in blocks of the same value
    :5f       Find all blocks of 1s (Pred 5)
    :la       The list of lengths of the blocks results in the indicator (given as output)
    
  • 술어 5 : 1의 블록에 대해서는 참, 그렇지 않으면 거짓

    e.        Output is an element of the input
      h1,     Its first value is 1
    

작업을위한 완벽한 도구 인 것 같습니다. 설명을 기대합니다.
Emigna

@ Fatalize 이것은 환상적입니다. 누군가가 프롤로그 같은 언어를 사용하여 이것을하기를 기다리고있었습니다. 25x25 케이스로 사용해 보셨습니까? 나는 이미
gowrath

@gowrath 나는 오늘 오후 내 컴퓨터에서 이것을 실행할 것입니다, 우리는 어떻게되는지 볼 것입니다.
치명적

@ Fatalize 시간이 초과 된 것 같지만 잘못하고있을 수 있습니다. 나는 데이터 입력 기술에 전적으로 의존하지 않을 것이다. : D
gowrath

@gowrath TIO에서 시간이 초과되었지만 내 컴퓨터의 오프라인 통역사에서 직접 실행합니다.
치명적

9

하스켈, 24223020199177163160149131 바이트

import Data.Lists
m=map
a#b=[x|x<-m(chunk$length b).mapM id$[0,1]<$(a>>b),g x==a,g(transpose x)==b]
g=m$list[0]id.m sum.wordsBy(<1)

마지막으로 200 바이트 미만으로 @Bergi에 기여합니다. 크기를 거의 절반으로 줄 이도록 도와 준 @nimi에게 큰 감사를드립니다.

와우. 거의 절반 크기로, 부분적으로 나 때문에 주로 @nimi 때문입니다.

마법의 기능은 (#)입니다. 주어진 비노 그램의 모든 솔루션을 찾습니다 .

이것은 모든 경우를 해결할 수 있지만 복잡도가 약하기 때문에 매우 느릴 수 있습니다 O(2^(len a * len b)). 빠른 벤치 마크 결과 5x5 비노 그램에 86GB가 할당되었습니다.

재미있는 사실 : 정사각형뿐만 아니라 모든 비노 그램에 적용됩니다.


작동 방식 :

  • a#b: 제곱 수를 나타내는 정수 목록이 제공된 경우 모든 그리드 ( map(chunk$length b).mapM id$a>>b>>[[0,1]])를 생성 하고 유효한 것만 유지하도록 결과를 필터링하십시오.
  • g: 잠재적 인 노노 그램이 주어지면 수평으로 1의 런을 합합니다.

O ((len a * len b) ^ 2)가 아니라 O (2 ^ (len a * len b))를 의미합니다.
Anders Kaseorg

@AndersKaseorg 맞습니다. 내가 실수로 암시 한 백만을 유지하십시오. : D
ThreeFx

1
또 다른 몇 바이트 : m(chunk$l b)replicate(l$a>>b)
BERGI

@ThreeFx 86GB : O ... Btw 이것을 컴파일하는 방법을 간단히 설명해 주시겠습니까? 나는 방금 haskell을 배우기 시작했고 이것은 ghc에 오류를주고 있습니다. 그것을 테스트하고
싶을

1
import Data.Lists이 때문에 다시 수출 모두 충분 Data.List하고 Data.List.Split.
nimi

4

Pyth, 91 72 71 바이트

D:GHdRq@@QdG.nCf.)TrH8V^,01^hQ2=TcNhQ=Y1VhQ=*Y*:H@TH1:H@CTH2)IYjbmjkdTb

[size, [horizontal clues], [vertical clues]]각 단서가 정수의 목록 인 양식 목록을 입력하고 (빈 단서는 빈 목록 []) 빈 줄로 구분 된 모든 솔루션을 1음영 처리되고 음영 처리되지 0않은 이진 격자 형식으로 인쇄하는 프로그램 .

이것은 무차별적인 힘이므로 대략 그렇습니다 O(2^n^2). 더 큰 퍼즐을 만드는 데 시간이 오래 걸리지 만 충분한 시간이 주어지면 임의의 크기를 해결할 수 있습니다.

온라인으로 사용해보십시오

작동 원리

프로그램 [0, 1]은 길이가 같은 카티 전 곱을 반복하여 가능한 모든 레이아웃을 생성 합니다 size^2. 그런 다음 청크로 분할되어 각 수평선에 대한 목록을 제공합니다. 각 라인은 런-길이 인코딩되고, 존재 1및 평탄화에 의해 필터링되어, 그 라인에 대한 실마리를 남깁니다. 그런 다음 입력과 비교하여 점검됩니다. 청크의 조옮김에 대해 상기 과정이 반복되어 수직선을 점검한다. 적중이 있으면 각 청크가 연결되고 연결된 청크가 줄 바꿈에 결합되고 후행 줄 바꿈으로 내재적으로 인쇄됩니다.

D:GHdRq@@QdG.nCf.)TrH8V^,01^hQ2=TcNhQ=Y1VhQ=*Y*:H@TH1:H@CTH2)IYjbmjkdTb  Program. Input: Q
                            hQ                                           Q[0], size
                           ^  2                                          Square
                        ,01                                              [0, 1]
                       ^                                                 Cartesian product
                      V                                     )            For N in the Cartesian product:
                                 cNhQ                                    Split N into Q[0] chunks
                               =T                                        Assign that to T
                                     =Y1                                 Y=1
                                        VhQ                              For H in range [0, Q[0]-1]:
D:GHd                                                                     def :(G, H, d)
                   rH8                                                     Run-length-encode(H)
               f.)T                                                        Filter by presence of 1 in character part
            .nC                                                            Transpose and flatten, giving the clue
       @@QdG                                                               Q[d][G], the relevant input clue
     Rq                                                                    Return clue==input clue
                                               :H@TH1                     :(H, T, 1)
                                                     :H@CTH2              :(H, transpose(T), 2)
                                           =*Y*                           Y=Y*product of above two
                                                             IY           If Y:
                                                                 mjkdT     Conacatenate each element of T
                                                               jb          Join on newlines
                                                                      b    Add a newline and implicitly print

몇 가지 팁을 주신 @ Pietu1998에게 감사합니다.


이것은 내가 본 것 중 가장 긴 Pyth 프로그램 일 수 있습니다
Business Cat

=ZhZ같은지 =hZFN같다 V.
PurkkaKoodari

@TheBikingViking 충분한 시간이 주어진다는 것은 정확히 무엇을 의미합니까? 나는 우주의 개념에서 시작했다면 지금까지 25x25를 해결하지 못할 것이라고 확신합니다.
gowrath

1
@ gowrath 나는 또한 그것을 확신합니다! 나는 Pyth를 처음 접했고, 오랜 시간이 지난 후에도 더 나은 알고리즘을 구현하는 것을 고려하고 싶지도 않습니다.
TheBikingViking

2

자바 (ES6) 401 386 333 바이트

이것은 초기 시도입니다. 그것은 효율적이지 않지만 행과 열의 이진 표현에 정규 표현식을 사용하여 솔루션을 테스트하는 것이 궁금했습니다.

예를 들어 단서 [3,1]를 다음과 같은 정규식으로 변환합니다 .

/^0*1{3}0+1{1}0*$/

현재이 버전은 사각형 단서를 고려하지 않았습니다. 나중에 이것을 추가 할 것입니다.

암호

(c,r)=>{W=c.length;w=[];S=0;M=(n,p)=>eval(`/^0*${p.map(v=>`1{${v}}`).join`0+`}0*$/`).exec(n);R=(y,i=0)=>S||(w[y]=r[y][i],y+1<W?R(y+1):c.every((c,y)=>(n=0,w.map((_,x)=>n+=w[W-1-x][y]),M(n,c)))&&(S=w.join`
`),r[y][i+1]&&R(y,i+1));r=r.map(r=>[...Array(1<<W)].map((_,n)=>((1<<30)|n).toString(2).slice(-W)).filter(n=>M(n,r)));return R(0)}

산출

솔루션은 이진 형식으로 표시됩니다. 같은 :

00110
01110
11100
11101
00001

테스트

이것은 예제 그리드에서 간단한 테스트입니다.

let f =
(c,r)=>{W=c.length;w=[];S=0;M=(n,p)=>eval(`/^0*${p.map(v=>`1{${v}}`).join`0+`}0*$/`).exec(n);R=(y,i=0)=>S||(w[y]=r[y][i],y+1<W?R(y+1):c.every((c,y)=>(n=0,w.map((_,x)=>n+=w[W-1-x][y]),M(n,c)))&&(S=w.join`
`),r[y][i+1]&&R(y,i+1));r=r.map(r=>[...Array(1<<W)].map((_,n)=>((1<<30)|n).toString(2).slice(-W)).filter(n=>M(n,r)));return R(0)}

console.log(f(
  [[2],[3],[4],[2],[2]],
  [[2],[3],[3],[3,1],[1]]
));


좋은 생각. 그래도 크리스마스 퍼즐에서 내 브라우저를 죽입니다.
Titus

2

하스켈, 109 바이트

면책 조항 : 이것은 @ThreeFx의 답변 에서 파생됩니다 . 나는 그에게 그의 대답을 알려주는 데 도움을 주었지만, 그는 마지막으로 개선 된 부분을 포함시키기 위해 관심을 잃어버린 것 같습니다.

import Data.List
n=mapM id
a#b=[x|x<-n$(n$" #"<$a)<$b,g x==a,g(transpose x)==b]
g=map$max[0].map length.words

사용 예 : [[2],[3],[3],[3,1],[1]] # [[2],[3],[4],[2],[2]]-> [[" ## "," ### ","### ","### #"," #"]].

무차별 대입 및의 모든 조합을 시도하고 #int 덩어리를 나누고 #길이를 세고 입력과 비교하십시오.


1

PHP, 751 833 (720) 753 724 726 710 691 680 682 바이트

나는 특별한 시퀀스 증분을 만들고 내 직교 생성기를 한번 더 시도하기를 열망했다.
그러나 큰 퍼즐을 더 빨리 풀기 위해 역 추적에 찬성하여 데카르트를 삭제했습니다.

$p=[];foreach($r as$y=>$h){for($d=[2-($n=count($h)+1)+$u=-array_sum($h)+$w=count($r)]+array_fill($i=0,$n,1),$d[$n-1]=0;$i<1;$d[0]+=$u-array_sum($d)){$o=$x=0;foreach($d as$i=>$v)for($x+=$v,$k=$h[$i];$k--;)$o+=1<<$x++;if(($s[$y]|$o)==$o){$p[$y][]=$o;$q[$y]++;}for($i=0;$i<$n-1&$d[$i]==($i?1:0);$i++);if(++$i<$n)for($d[$i]++;$i--;)$d[$i]=1;}}
function s($i,$m){global$c,$w,$p;for(;!$k&&$i[$m]--;$k=$k&$m<$w-1?s($i,$m+1):$k){for($k=1,$x=$w;$k&&$x--;){$h=$c[$x];for($v=$n=$z=$y=0;$k&&$y<=$m;$y++)$n=$n*($f=($p[$y][$i[$y]]>>$x&1)==$v)+$k=$f?:($v=!$v)||$n==$h[$z++];if($k&$v)$k=$n<=$h[$z];}}return$k?is_array($k)?$k:$i:0;}
foreach(s($q,0)as$y=>$o)echo strrev(sprintf("\n%0{$w}b",$p[$y][$o]));
  • $r행 힌트, $c열 힌트 및 $s사각형 힌트에 대한 배열의 힌트를 예상합니다 .
  • invalid argument supplied for foreach해결책이 없으면 던집니다 .
  • 올바른 바이트 수를 얻으려면 물리를 사용 \n하고 다른 두 줄 바꿈을 제거하십시오.

기술

1) 행 힌트
에서 사각형 힌트를 만족시키는 가능한 행을 생성
하고 각 행 인덱스의 수를 기억하십시오.

2) 행 조합에 대한 역 추적 :
조합이 열 힌트를 만족하는 경우 더 깊게 검색하거나 성공적인 조합을 반환
하면이 행에 대해 다음 가능성을 시도하십시오.

3) 인쇄 솔루션


마지막 골프는 성능에 심각한 영향을 미쳤습니다.
그러나 최종 벤치 마크에 대한 프로파일 링 할당을 제거했습니다.

교체 $n=$n*($f=($p[$y][$i[$y]]>>$x&1)==$v)+$k=$f?:($v=!$v)||$n==$h[$z++];
if(($p[$y][$i[$y]]>>$x&1)-$v){$k=($v=!$v)||$n==$h[$z++];$n=1;}else$n++;
마지막 골프 단계를 취소 할 수 있습니다.

작은 예 ( 17 ~ 2112 8 7 6.7 5.3 ms)의 경우

$r=[[2],[3],[3],[3,1],[1]];$c=[[2],[3],[4],[2],[2]];$s=[0,0,0,0,0];

크리스마스 퍼즐 :

  • 오래된 솔루션으로 작은 홈 서버를 죽였습니다.
  • 테스트 출력으로 브라우저를 죽였습니다.
  • 이제 50 37.8 45.5 약 36 초에 해결되었습니다.

질문의 데이터를 파일 christmas.nonogram에 넣고이 코드를 사용하여 가져옵니다.

$t=r;foreach(file('christmas.nonogram')as$h)if('-'==$h=trim($h))$t=c;elseif('#'==$h){$t=s;$f=count($h).b;}else
{$v=explode(' ',$h);if(s==$t)for($h=$v,$v=0,$b=1;count($h);$b*=2)$v+=$b*array_shift($h);${$t}[]=$v;}

고장

$p=[];  // must init $p to array or `$p[$y][]=$o;` will fail
foreach($r as$y=>$h)
{
    // walk $d through all combinations of $n=`hint count+1` numbers that sum up to $u=`width-hint sum`
    // (possible `0` hints for $h) - first and last number can be 0, all others are >0
    for(
        $d=[2-
            ($n=count($h)+1)+               // count(0 hint)=count(1 hint)+1
            $u=-array_sum($h)+$w=count($r)  // sum(0 hint) = width-sum(1 hint)
        ]                           // index 0 to max value $u-$n+2
        +array_fill($i=0,$n,1)      // other indexes to 1
        ,$d[$n-1]=0;                // last index to 0
                                    // --> first combination (little endian)
        $i<1;   // $i:0 before loop; -1 after increment; >=$n after the last combination
        $d[0]+=$u-array_sum($d) // (see below)
    )
    {
        // A: create row (binary value) from 1-hints $h and 0-hints $d
        $o=$x=0;
        foreach($d as$i=>$v)
            for($x+=$v,$k=$h[$i];$k--;)
                $o+=1<<$x++;
        // B: if $o satisfies the square hints
        if(($s[$y]|$o)==$o)
        {
            $p[$y][]=$o;    // add to possible combinations
            $q[$y]++;       // increase possibility counter
        }
        // C: increase $d
            // find lowest index with a value>min
                // this loop doesn´t need to go to the last index:
                // if all previous values are min, there is nothing left to increase
        for($i=0;$i<$n-1&$d[$i]==($i?1:0);$i++);
        if(++$i<$n)             // index one up; increase $d if possible
            for($d[$i]++        // increase this value
            ;$i--;)$d[$i]=1;    // reset everything below to 1
            // adjust $d[0] to have the correct sum (loop post condition)
    }
}

// search solution: with backtracking on the row combinations ...
function s($i,$m)
{
    global $c,$w,$p;
    for(;
        !$k // solution not yet found
        &&$i[$m]    // if $i[$m]==0, the previous iteration was the last one on this row: no solution
            --;     // decrease possibility index for row $m
        $k=$k&$m<$w-1? s($i,$m+1) : $k      // if ok, seek deeper while last row not reached ($m<$w-1)
    )
    {
        // test if the field so far satisfies the column hints: loop $x through columns
        for($k=1,$x=$w;$k&&$x--;)   // ok while $k is true
        {
            $h=$c[$x];
            // test column hints on the current combination: loop $y through rows up to $m
            for($v=$n=$z=   // $v=temporary value, $n=temporary hint, $z=hint index
                $y=0;$k&&$y<=$m;$y++)
                // if value has not changed, increase $n. if not, reset $n to 1
                // (or 0 for $k=false; in that case $n is irrelevant)
                $n=$n*  
                    // $f=false (int 0) when value has changed, true (1) if not
                    ($f=($p[$y][$i[$y]]>>$x&1)==$v)
                    +$k=$f?:    // ok if value has NOT changed, else
                        ($v=!$v)        // invert value. ok if value was 0
                        || $n==$h[$z    // value was 1: ok if temp hint equals current sub-hint
                        ++]             // next sub-hint
                ;
            // if there is a possibly incomplete hint ($v==1)
            // the incomplete hint ($n) must be <= the next sub-hint ($c[x][$z])
            // if $n was <$h[$z] in the last row, the previous column hints would not have matched
            if($k&$v)$k=$n<=$h[$z];
        }
        // ok: seek deeper (loop post condition)
        // not ok: try next possibility (loop pre condition)
    }
    return$k?is_array($k)?$k:$i:0;  // return solution if solved, 0 if not
}

// print solution
foreach(s($q,0)as$y=>$o)echo strrev(sprintf("\n%0{$w}b",$p[$y][$o]));

1
큰 예제는 작은 홈 서버를 종료합니다 (500-내부 서버 오류). 조합은 15 secons 후에 준비되었지만 직교 곱에는 1.823E + 61 멤버가 있습니다. (7 번째와 22 번째 행에는 btw가 하나만 있습니다.) 알고리즘을 개선해야합니다.
Titus

재귀 역 추적을 사용하면 이것이 가속화 될 수 있다고 생각합니다. 그럼에도 불구하고 훌륭한 일입니다!
gowrath

@gowrath : 역 추적은 비트를 제공하고 바이트를 절약합니다 ... 비트 산술을 가진 정수는 약 50 %의 속도를 제공하지만 크기는 증가합니다 (정확한 비용은 얼마인지 알아 내야 함) ... 나는 여전히 그 위에 있습니다.
Titus

@ gowrath : 나는 내 버그를 쫓았 다. 그것은 증가 (다른 곳에서?)에 있었다 :$dforeach
Titus
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.