Algorithm
백준
Python
사다리 조작

15684 사다리 조작

풀이 1

좀 더 직관적으로 이해하기가 편한 풀이, 백트래킹으로 모든 사다리를 조회하면서 최소값을 찾는 풀이이다.

import sys
 
def check():
    for start in range(N):
        k = start
        for j in range(H):
            if board[j][k]:
                k += 1
            elif k > 0 and board[j][k - 1]:
                k -= 1
        if k != start: return False
    return True
 
def dfs(cnt, x, y):
    global ans
    if check():
        ans = min(ans, cnt)
        return
    elif cnt == 3 or ans <= cnt:
        return
    for i in range(x, H):
        if i == x: k = y
        else: k = 0
        for j in range(k, N - 1):
            # 지금 현재 자리와 다음 자리에 사다리가 없다면
            if not board[i][j] and not board[i][j + 1]:
                # 왼쪽에 사다리 있으면 통과
                if j > 0 and board[i][j - 1]: continue
                board[i][j] = True
                dfs(cnt + 1, i, j + 2)
                board[i][j] = False
 
if __name__ == '__main__':
    N, M, H = map(int, sys.stdin.readline().split())
    board = [[False] * N for _ in range(H)]
    if M == 0:
        print(0)
        exit(0)
    for _ in range(M):
        a, b = map(int, sys.stdin.readline().split())
        board[a - 1][b - 1] = True
    ans = 4
    dfs(0, 0, 0)
    print(ans if ans < 4 else -1)

풀이 2

def check():
    for sj in range(1, N+1):    # 모든 sj값이 끝날때도 같아야 성공!
        j = sj
        for i in range(1, H+1):
            if arr[i][j]==1:    # 오른쪽으로 이동
                j+=1
            elif arr[i][j-1]==1:# 왼쪽으로 이동
                j-=1
        if j!=sj:
            return 0            # 하나라도 다르다면 실패
    return 1
 
def dfs(n, s):
    global ans
    if ans==1:      # 가지치기
        return
 
    if n==cnt:      # 모든 개수를 선택완료
        if check()==1:
            ans=1
        return
 
    for j in range(s, CNT):
        ti,tj = pos[j]
        # 왼쪽도 사다리가 아니고, 오른쪽도 사다리가 아니면 가능!
        if arr[ti][tj-1]==0 and arr[ti][tj+1]==0:
            arr[ti][tj]=1
            dfs(n+1, j+1)
            arr[ti][tj]=0
 
N, M, H = map(int, input().split())
 
# [1] 사다리 입력 받기 (문제 좌표와 직관적으로 일치)
arr = [[0]*(N+2) for _ in range(H+1)]   # 좌우 공백추가(범위체크X)
for _ in range(M):
    ti,tj = map(int, input().split())   # 미리 놓아져 있는 사다리표시
    arr[ti][tj]=1
 
# [2] 사다리 놓을 후보 저장
pos = []
for i in range(1, H+1):
    for j in range(1, N+1):
        if arr[i][j]==0 and arr[i][j-1]==0 and arr[i][j+1]==0:
            pos.append((i,j))
CNT = len(pos)
 
# [3] 추가하는 사다리개수 0~3 실행 => 안되면 -1이 정답
for cnt in range(4):
    ans = 0
    dfs(0,0)    # CNT개에서 cnt개수를 뽑는 모든 조합
    if ans==1:
        ans = cnt
        break
else:           # 발견하지 못했다면 break안했음..
    ans = -1
print(ans)

Reference

https://www.youtube.com/watch?v=KpLa9nb7Gj8&t=1378s (opens in a new tab)