2D 미로 빼기 1D


27

이 과제는 2D 미로를 1D 미로로 변환하는 것입니다.

개요

+-+-+-+-+-+-+   +-+-+-+-+-+-+                    graph {
| |   |     |   |A|   |    B|   A         B        A -- D
+ + + + +-+-+   + + + + +-+-+    \        |        C -- D
|   | |     |   |   | |     |     \       |        D -- E
+-+-+ +-+-+ +   +-+-+ +-+-+ +      \      |        E -- F
|           |   |C   D E   F|   C---D-E---F        E -- G
+-+-+-+ +-+ +   +-+-+-+ +-+ +         |   |        B -- F
|         | |   |      G  | |     .---G   |        F -- J
+ +-+-+-+ + +   + +-+-+-+ + +   .'   /    |        G -- H
| |       | |   |H|I      |J|   H I-'     J        G -- I
+-+-+-+-+-+-+   +-+-+-+-+-+-+     (ascii)        } // (graphviz dot)       
   Figure 1       Figure 2                 Figure 3

이 도전의 목적을 위해, 전통적인 2D 미로는 격자 점으로 형성된 직사각형 미로입니다.

  • 닫혀 있습니다 (외부 림은 벽으로 연결됨).
  • 모든 격자 점은 벽에 연결됩니다
  • 연결되어 있습니다 (두 칸마다 X와 Y 사이에 경로가 있습니다)
  • 비 주기적입니다 (역 추적없이 공간 X에서 X 로의 경로가 없습니다)

그림 1은 전통적인 2D 미로를 보여줍니다. 이 미로는 관심 분야가 3 가지 있습니다.

  • 막 다른 골목 -사용 가능한 경로가 하나 뿐인 곳
  • 복도 -사용 가능한 경로가 두 개있는 장소
  • 결정 지점 -사용 가능한 경로가 3-4 개있는 곳

그러한 미로마다, 데드 엔드와 결정 포인트가 노드 인 그래프를 생성 할 수 있으며 복도를 따라 경로로 연결된 두 노드 사이에 가장자리가 있습니다. 그림 2는 이러한 노드에 레이블이 붙은 동일한 미로를 나타내고 그림 3은 미로의 그래프 (ASCII 및 Graphviz 도트 표기법으로 표시)입니다.

1D 미로

1D 미로는 뒤틀림 지점을 포함하며 쌍으로되어 있으며 문자를 사용하여 식별됩니다 (두 경우 모두). 그림 4는 1D 미로의 예를 보여줍니다. 이것은도 5에 도시 된 바와 같이, 높이가 1 인 2D 미로와 동일하다. 특히도 5에서 +, 로 표시된 격자 점 위치는 왼쪽에서 오른쪽으로 교대 로 나타난다 ; 1D 미로에서 가장 왼쪽 벽으로 시작하는 다른 모든 문자도 격자 점입니다.

                                 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|  D|  D E|G E F|  F  |  G  |    |  D|  D E|G E F|  F  |  G  |
                                 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+
            Figure 4                         Figure 5

이 미로를 탐색하는 규칙은 다음과 같습니다. 모든 움직임은 앞으로 ( >) 또는 뒤로 ( <) 로 표시 될 수 있습니다 . 여기에서 앞뒤로 기본적으로 직관적 인 공간 인식과 같은 의미를 갖습니다. 앞으로 오른쪽으로 즉시 이동하고 왼쪽으로 뒤로 이동합니다.

변형 점은 연결을 비대칭 적으로 이웃과 교환하는 위치를 나타냅니다. 이웃에서 날실 지점으로 오는 경우 두 날실 지점의 위치가 바뀝니다. 워프 지점에서 이웃으로 오는 경우 서로 바뀌지 않습니다. 예를 들어, 그림 6에서 1에서 뒤로 이동하면 2로 이동합니다 (1이 G의 이웃이기 때문에 이웃에서 이동하기 때문에 점 2와 @가 교환 됨). 2 (워프 포인트 G)에서 앞으로 이동하면 3으로 이동합니다 (여기서 워프 포인트에서 시작하므로 스왑이 없습니다). 마찬가지로 3에서 뒤로 이동하면 @로 이동합니다.

        54 2367    89^   @1
|  D|  D E|G E F|  F  |  G  |
                     Y     X
          Figure 6

그림 6은 일련의 이동을 사용하여 X에서 Y로 이동하는 예제를 보여줍니다 <<>><>>>>>. 이러한 동작 123456789^은 순서대로 각각 레이블이 지정된 지점으로 이동합니다 . 다음 섹션의 코드 스 니펫을 사용하여 자유롭게 탐색하십시오.

2D를 1D로 변환

1D 미로가 주어지면, 각각의 노드가 막 다른 골목 또는 날 실점 쌍이고 그래프가 복도를 따라 연결된 두 노드 사이에 존재하는 그래프를 만들 수 있습니다. 이 그래프를 통해 1D와 2D 미로를 비교할 수 있습니다.

예를 들어, 그림 4의 1D 미로는 그림 1의 동일한 미로입니다. 이유를보기 위해 그림 7은 막 다른 곳에 레이블을 추가합니다. 이 레이블을 사용하여 그래프를 작성하면 그림 7의 그래프는 다시 그림 3입니다. 그림 8은이 그래프를 구성한 것입니다.

|  D|  D E|G E F|  F  |  G  |
 A   C           B   J H   I 
          Figure 7

|  D|  D E|G E F|  F  |  G  |
+ + + + + + + + + + + + + + + <- lattice points
|A  |C    |     |B   J|H   I| <- dead ends
|A D|C D E|G E F|B F J|H G I| <- all nodes (dead ends+warp points); i.e.:
                                 "where each end is either a dead end
                                  or a warp point pair"; note that each
                                  pair of warp points is the same node.
|A-D|C-D-E|G-E-F|B-F-J|H-G-I| <- corridors; note each is a connection, since
  1   2 3   4 5   6 7   8 9      "edges exist between any two nodes
                                  connected along a corridor"
   graph {                 graph {                 
     A -- D  // 1 <---->     A -- D                
     C -- D  // 2 <---->     C -- D                
     D -- E  // 3 <---->     D -- E                
     G -- E  // 4 <---->     E -- G                
     E -- F  // 5 <---->     E -- F                
     B -- F  // 6 <---->     B -- F                
     F -- J  // 7 <---->     F -- J                
     H -- G  // 8 <---->     G -- H                
     G -- I  // 9 <---->     G -- I                
   }                ^      }
    Built from      |      From Figure 3
     1D maze         `-> isomorphic mappings
                Figure 8

(각 그래프의 레이블과 레이아웃은 설명 목적으로 정렬되도록 인위적으로 선택되었습니다. 일반적으로 그래프 동 형사상 문제입니다 ).

다음 스 니펫은 1D 미로의 역학과 1D 미로, 등가 그래프 및 2D 미로 간의 연결을 시각화하는 데 도움이되도록 제공됩니다.

이 스 니펫에서 1D 미로를 탐색하면 마지막 두 노드가 강조 표시됩니다. 동등 노드와 2D 미로에서 동일한 노드가 같은 방식으로 강조 표시됩니다.


일반적으로 기존의 2D 미로의 경우이 유형의 동등한 1D 미로를 만들 수 있습니다. 약간 더 복잡한 예는 그림 9입니다.

+-+-+-+-+-+-+   +-+-+-+-+-+-+                   graph {
| |   |   | |   |A|   |   |B|   A         B       A -- D
+ + + + + + +   + + + + + + +    \       /        C -- D
|   | | |   |   |   | | |   |     \     /         D -- E
+-+-+ + +-+-+   +-+-+ + +-+-+      \   /          B -- E
|           |   |C   D E    |   C---D-E           E -- F
+-+-+-+ +-+ +   +-+-+-+ +-+ +         |\          E -- I
|         | |   |      F  | |     .---F \         F -- G
+ +-+-+-+ + +   + +-+-+-+ + +   .'   /   \        G -- H
| |       | |   |G|H      |I|   G H-'     I       H -- I
+-+-+-+-+-+-+   +-+-+-+-+-+-+     (ascii)       } // (graphviz dot)
   Figure 9       Figure 10             Figure 11

|  D|  D E  |F E  |  F  |       |  D|  D E  |F E  |  F  |
                                 A   C     I     B G   H
      Figure 12                       Figure 13

이 미로는 경로가 네 개인 노드를 가지고 있습니다 (그림 10의 E). 그림 11은 그래프를 보여줍니다. 도 12는 동등한 1D 미로이다. 그리고 그림 13은 그림 11과 비교할 수있는 막 다른 라벨이있는 동일한 미로를 보여줍니다.

도전

2D 미로를 입력으로 받으면 2D 미로를 날 실점이있는 1D 미로로 변환하는 함수 나 프로그램을 작성하십시오. 뒤틀림 포인트는 각 52 개의 문자를 사용할 수 있습니다.

입력 보장 (입력에서 충족되지 않은 경우 처리 할 필요가 없음) :

  • 입력 미로가 연결되어 있습니다 (즉, 언제 어디서나 다른 곳으로 갈 수 있습니다).
  • 입력 미로가 닫힙니다.
  • 입력 미로는 직사각형입니다.
  • 모든 격자 점은를 사용 +합니다.
  • 같은 행에서 격자 점 사이의 모든 벽은 |
  • 동일한 기둥에서 격자 점 사이의 모든 벽이 사용 -됩니다.
  • 모든 공간은 경로의 일부입니다 (그리고 모두 미로 내부).
  • 경로는 모든 공간입니다 (이것은 항상 전통적이고 뒤 틀리지 않습니다)
  • 경로는 정확히 하나의 공간 너비입니다.
  • 미로는 격자의 점을 연결하여 만들어집니다.
  • 미로의 그래프에는 총 노드 수가 52 개를 넘지 않습니다 (즉, 데드 엔드 + 결정 포인트).

출력 형식:

  1. 출력은 1D 미로를 보여주는 한 줄 이어야합니다 .
  2. 출력에는 선행 / 후행 공백이 없어야합니다. 후행 줄 바꿈은 괜찮습니다.
  3. 첫 문자와 다른 모든 문자는 격자 점입니다.
  4. 모든 벽은 격자 점에 있어야합니다. 그리고 그들 사이의 모든 왜곡 점.
  5. 1D 미로의 그래프는 2D 미로의 그래프와 동일해야합니다.
  6. 1D 미로는 작아야합니다. 격자가 아닌 모든 점은 막 다른 곳 (즉, 벽에 인접)이거나 변형 점이되어야합니다.
  7. 문자 만 당신의 출력은 워프 지점이어야한다. 각 워프 포인트는 선에서 정확히 두 번 발생합니다.

예:

|  D|  D E|G E F|  F  |  G  | <- (1,2) The single line output
+ + + + + + + + + + + + + + + <- lattice point spacing... (3) 
                                 (4,6) lattice points are all walls or spaces
                                 (5) See Figure 8
                                 (7) D, E, F, G appear twice; no other labels

이것은 코드 골프입니다. 승자는 바이트 수가 가장 적은 정확한 비루 홀 제출입니다.

테스팅

사소한 미로에 대한 많은 올바른 출력이 있기 때문에이 도전에 대한 테스트 사례는 없습니다.

그러나 C ++로 체커를 만들었습니다 (이 체커는 두 가지 솔루션을 그래프 정규화를 통해 그래프로 표시합니다 ).

또한 올바른 형식을 설명하는 데 도움이되는 몇 가지 예가 있습니다.

실시 예 1

+-+-+-+-+-+-+
| |   |     |
+ + + + +-+-+
|   | |     |
+-+-+ +-+-+ +
|           |
+-+-+-+ +-+ +
|         | |
+ +-+-+-+ + +
| |       | |
+-+-+-+-+-+-+
->
|  D|  D E|G E F|  F  |  G  |

실시 예 2

+-+-+-+-+-+-+
| |   |   | |
+ + + + + + +
|   | | |   |
+-+-+ + +-+-+
|           |
+-+-+-+ +-+ +
|         | |
+ +-+-+-+ + +
| |       | |
+-+-+-+-+-+-+
->
|  D|  D E  |F E  |  F  |

더 많은 예제는 여기에서 찾을 수 있습니다 .


1
1D 미로에 대한 설명이 전혀 명확하지 않다고 생각합니다. 작거나 간단한 예제를 추가하면 도움이 될 것입니다.
mbomb007

꽤 괜찮은데. 그래 그게 도움이된다.
mbomb007

대화식 스크립트가 도움이되었지만 여전히 어려운 문제입니다. 그래서 나는 그것을 건너 뜁니다. 이것에 대한 나의 이해는 여전히 부족합니다.
mbomb007

1D 미로의 설명은 스케치입니다. 1D 미로의 세로 막대 문자가 통과 할 수없는 벽이라는 것을 이해하기 위해 그림 7까지 읽어야했습니다.
edc65

1
: 1 차원 미로 예 1은 문자의 각 쌍은 사다리입니다 차원 미로에 쌓아 gist.github.com/sparr/36d6355cc4c785a27b12157666169082
Sparr

답변:


3

igraph가 포함 된 Python 2 , 492 369 바이트

import igraph,string
def f(s):
 C=s.find('\n')/2;N=' ';g=igraph.Graph(0,[(i,i+j)for i in range(len(s)/(4*C+4)*C)for j in(1,C)if s[(i/C*2+1)*(2*C+2)+i%C*2+2*j+j/C*3]==N]);V=g.vs;g.d=g.degree;O='';V(_d=1)[N]=N;V(_d_gt=2)[N]=list(string.ascii_letters)
 while g.es:
    v=V(_d=1)[0];O+='|'+v[N]
    while g.d(v):w=v.neighbors()[0];g-=(v,w);v=w;O+=N+v[N]if v[N]else''
 print O+'|'

(5 번째와 6 번째 줄은 각각 StackExchange가 보여 주듯이 4 개의 공백이 아닌 탭으로 시작합니다.)

  • 6 바이트를 저장하여 약간의 산술 정리
  • zip 대신 슬라이스를 사용하여 7 바이트 저장
  • g+=tuple(v.neighbors())대신에 3 바이트를 절약했습니다.g.add_edge(*v.neighbors())
  • g-=g.es[g.incident(v)]대신에 7 바이트를 절약했습니다.g.delete_edges(g.incident(v))
  • 11 바이트 앨리어싱 저장 g.d=g.degree
  • 2 바이트 정점을 이웃 사이의 모서리로 대체하여 모든 복도를 수축시키는 루프를 제거하여 52 바이트 (!)를 절약했습니다. 대신 출력 루프는 이러한 정점을 무시합니다.
  • 이름을 지정할 때 제공된 iterable이 너무 길어도 igraph는 신경 쓰지 않음을 인식하여 13 바이트를 절약
  • R행 수에 대한 변수가 없어 계산을 유일한 사용 지점으로 이동하여 4 바이트를 절약했습니다.
  • 두 번째 수준 들여 쓰기를 공백 대신 탭으로 변경하여 2 바이트를 절약했습니다.
  • 저장된 여섯 바이트 정리 2*(i%C)i%C*2, 2*(i/C)i/C*2, 그리고 (C-1)*jj*C-j
  • 4 바이트 이름 저장 N='n'
  • 캐릭터가 사용하는 공간 인 경우 1 바이트를 결정 저장된 <'-'보다는이 ==' '유효한 문자가 표시 있다는 가정하에.
  • 그런 다음 ' '대신 vertex 속성의 이름을 지정하고 소스에서 두 개의 리터럴 공백을 'n'재사용 N하고 ==N대신 <'-'5 바이트를 절약 할 수 있음을 깨달았습니다.

다소 골 판이없는 버전이 이어집니다. 기본 아이디어는 먼저 모든 미로 정점에 그래프를 작성하는 것입니다 (0으로 색인을 생성 할 때 행과 열이 홀수 인 점). 그리고 아닙니다 |. 다음 행의 해당 문자가 공백이 아닌 경우 꼭지점이 오른쪽 아래에있는 모서리가 있습니다 -.

이 그래프를 만든 후에는 잎을 골라 연속적으로 인접한 정점을 따라 가서 복도가 아닌 경우 이름을 쓰고 사용 된 가장자리를 삭제합니다. 그런 다음 다른 잎을 가져 와서 모든 가장자리가 사라질 때까지 계속하십시오.

import string
import igraph
def f(s):
  C = s.find('\n')/2 # number of maze vertices in each row
  R = len(s)/(4*C+4) # number of rows
  def strpos(r, c):
    """Index of the vertex at row r, col c in the newline-delimited string s"""
    return (2*r+1)*(2*C+2) + 2*c + 1
  def vertpos(i):
    """Index of the i-th vertex in s"""
    return strpos(i/C, i%C)
  g = igraph.Graph(edges=[(i, i+(C if j else 1))
                          for i in range(R*C)
                          for j in (0, 1)
                          if s[vertpos(i)+(2*C+2 if j else 1)] == ' '])
  V = g.vs # the graph's vertex sequence
  O = ''
  V(_degree=1)['n'] = ' ' # All leaves are named space
  W = V(_degree_gt=2) # All warp points...
  W['n'] = list(string.ascii_letters[:len(W)]) # ...are named successive letters
  while g.es: # while any edges remain...
    v = V(_degree=1)[0] # find a leaf
    O += '|'+v['n'] # start a new 'block'
    while v.degree():
      w = v.neighbors()[0] # pick a neighbor
      g -= (v, w) # delete that edge
      v = w
      if v['n']: # If it's a dead end or warp point...
        O += ' '+v['n'] # ...write out the new neighbor
  print O+'|'

5 개의 예제 미로에 대한 결과를 볼 수 있습니다 . (안타깝게도 igraphTry It Online에서는 사용할 수 없으며 이러한 결과는 SageMathCloud 에서 내보냈습니다 .)


4

하스켈 - 481 405 387 바이트

import Data.List
s&t=elemIndices s t
l=last
c!(x:y:z)=l$(y:c)!(x:z):do{[x:p,q]<-mapM([id,reverse]<*>)[[x],[y]];x&[l q];[[]!((q++p):c++z)]}
c![x]=x:[]!c
c!z=z
main=interact(\m->let{g=' '&m;
u=(\\[k|k<-g,length(v>>=(k&))==2])<$>[]!v;
v=[[x,y]|x<-g,y<-g,elem(y-x-1)[0,head$'\n'&m]];
}in '|':(u>>=(++"|").init.(>>=(:" ").toEnum.((+)<*>(+65).(*32).(`div`26)).l.(-1:).(&(nub$u>>=init.tail)))))

이렇게하면 문자열에 색인으로 번호가 매겨진 미로에있는 공간 목록이 만들어지고이를 사용하여 인접한 공간 쌍을 모두 찾습니다. 그런 다음 일치하는 첫 번째 / 마지막 요소를 기반으로 쌍을 더 긴 일련의 점으로 연결하고 복도를 제거하여 각 시퀀스가 ​​1D 미로에서 하나의 공간이되도록합니다. 그런 다음 시퀀스는 최소한 하나의 방 내부의 점 (워프 점)을 해당 문자로 바꾸고 나머지는 공백으로 바꾸어 문자열로 변환합니다.

STDIN에서 2D 미로를 읽고 1D 미로를 STDOUT으로 인쇄합니다.

편집 : (62)에 의해 감소는 대체하여 다른 14를 잔뜩 정리 및 알고리즘을 조금 수정 및 바이트 chrtoEnumLaikoni에 의해 제안.

편집 2 : 논리를 단순화하여 13 바이트를 절약하고 (!), 3은 목록 패턴 일치 설탕을 사용하여, 2는 >>=에 연결 하는 데 사용 합니다 u.


패턴 가드 앞에 줄 바꿈과 공백이 필요하지 않습니다 o(x:p)q|x==last q=[q++p]|1>0=[]. 예를 들어 작동해야합니다.
Laikoni

또한 toEnum대신에 작업을해야 chr다음 import Data.Char삭제 될 수 있습니다.
Laikoni

그리고 도전이 프로그램이나 기능을 요구할 때 main=interact(\m->...)그냥로 바꿀 수 있습니다 f m=.... 파이썬 답변을 이길 수 있다면 충분합니다.
Laikoni
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.