[BOJ] 사다리 조작 - DFS

김가영·2021년 3월 16일
0

Algorithm

목록 보기
73/78
post-thumbnail

15684: 사다리 조작 골드4 아 어려웠다.

import sys
input = sys.stdin.readline
from collections import deque

nvertical, nline, nhorizontal = list(map(int, input().split()))
toRight = set()

for _ in range(nline):
    hor, ver = list(map(int, input().split()))
    toRight.add((ver-1,hor-1))

v = deque([])
v.append((0, 0,0, set()))
answer = -1
while v:
    start, ver, hor, toR= v.pop()
    if hor == nhorizontal:
        if start == ver:
            if start == nvertical - 1:
                answer = len(toR)
                break
            else:
                v.append((start+1, start+1, 0, toR))
        continue
    while hor < nhorizontal:
        if (ver,hor) in toR or (ver,hor) in toRight:
            ver+=1
            hor+=1
            if hor == nhorizontal:
                v.append((start, ver, hor, toR))
        elif (ver-1, hor) in toR or (ver-1,hor) in toRight:
            ver-=1
            hor+=1
            if hor == nhorizontal:
                v.append((start, ver, hor, toR))
        else:
            if ver - 1 >= 0 and (ver-2, hor) not in toR and (ver-2, hor) not in toRight and len(toR) < 3: # 하나 빼줘도 될듯
                v.appendleft((start, ver-1, hor+1, toR | {(ver-1, hor)}))
            # 오른쪽
            if ver + 1 < nvertical and (ver+1,hor) not in toR and (ver+1, hor) not in toRight and len(toR) < 3:
                v.appendleft((start, ver+1, hor+1, toR | {(ver, hor)}))
            # 아래로 이동
            v.append((start, ver, hor+1, toR))
            break
print(answer)

아 너무 어려웠다.. 시간초과가 많이 났다. 보니까 대부분 PyPy3 로 해서 통과하고 Python3로 통과한 사람은 몇 없더라.

일단 기본 구조는,
toRight 는 사다리의 왼쪽 끝의 집합들이다.


while hor < nhorizontal:
      if (ver,hor) in toR or (ver,hor) in toRight:
          ver+=1
          hor+=1
          if hor == nhorizontal:
              v.append((start, ver, hor, toR))
      elif (ver-1, hor) in toR or (ver-1,hor) in toRight:
          ver-=1
          hor+=1
          if hor == nhorizontal:
              v.append((start, ver, hor, toR))
      else:
          if ver - 1 >= 0 and (ver-2, hor) not in toR and (ver-2, hor) not in toRight and len(toR) < 3: 
              v.appendleft((start, ver-1, hor+1, toR | {(ver-1, hor)}))
          # 오른쪽
          if ver + 1 < nvertical and (ver+1,hor) not in toR and (ver+1, hor) not in toRight and len(toR) < 3:
              v.appendleft((start, ver+1, hor+1, toR | {(ver, hor)}))
          # 아래로 이동
          v.append((start, ver, hor+1, toR))
          break
print(answer)

현재 세로선과 가로선 인덱스(ver, hor) 에 대하여
만약 오른쪽으로 가는 가로선이 있으면 오른쪽 하단으로 이동하고, 왼쪽으로 가는 가로선이 있으면 왼쪽 하단으로 이동하는 과정을 반복한다. (이동할 수 있는 선택권이 없는 상황)
현재 ver,hor 좌표에 아무 가로선이 없으면 1. 가로선을 왼쪽으로 생성하거나, 2. 가로선을 오른쪽으로 생성하거나, 3. 가로선 생성 없이 밑으로 내려가기 의 세 가지 방법이 있다.
while 문 내 if 문에서 else 문이 이에 대한 코드이다.

여기에서 시간을 줄여주기 위하여 가로선이 현재보다 늘어나면 v 왼쪽에 추가하고, 현재와 동일하면 v 오른쪽에 추가하는 방식을 추가했다. 이렇게 해주면 가장 작은 가로선 개수에 대해 먼저 탐색하게 되므로 원하는 조건을 충족하는 답이 나왔을 때 바로 답을 print 하고 다른 경우의 수를 살펴보지 않아도 된다.


위 코드의 상단에는

while v:
    start, ver, hor, toR= v.pop()
    if hor == nhorizontal:
        if start == ver:
            if start == nvertical - 1:
                answer = len(toR)
                break
            else:
                v.append((start+1, start+1, 0, toR))
        continue

계속해서 밑으로 나아가던 (ver,hor) 에 대하여 만약 hor == nhorizontal(가로선 최대)이면 (가로선 끝까지 좌표가 이동했다면) 현재 세로선이 시작한 세로선과 동일한 지 확인해준다.(i번 세로선 결과가 i이어야 함)

그러한 경우에는 원하는 조건을 만족하므로 다음 세로선의 처음부터 사다리타기를 시작한다. (v.append 부분)
만약 start == nvertical - 1 이면 (마지막 세로선까지 탐색이 끝났다면, 사실 마지막 세로선은 검사 안해줘도 된다) 탐색을 멈추고 답을 출력한다.

profile
개발블로그

0개의 댓글