일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 |
- 구현
- 자료구조
- 해시
- DFS
- 그래프 탐색
- 다이나믹프로그래밍
- 그리디
- 플로이드-워셜
- GROUP BY
- DP
- 투포인터
- 백트래킹
- join
- 크루스칼
- MST
- 다시
- 우선순위큐
- 재귀
- 시뮬레이션
- 트리
- 수학
- BFS
- 서브쿼리
- 에라토스테네스의 체
- 다이나믹 프로그래밍
- 다익스트라
- 누적합
- 분할정복
- 그래프 이론
- 브루트포스
- Today
- Total
기록하고 까먹지 말기
17070 본문
날짜 : 2023. 06. 23
사용 언어 : python
문제
코드
정답(DP 사용)
import sys
n = int(sys.stdin.readline())
graph = list()
for _ in range(n): graph.append(list(map(int, sys.stdin.readline().split())))
dp = [[[0] * n for _ in range(n)] for _ in range(3)]
dp[0][0][1] = 1 # 방향, r, c
for i in range(2, n):
if graph[0][i] == 0:
dp[0][0][i] = dp[0][0][i-1] # 가로 이동
for i in range(1, n):
for j in range(1, n):
# 현재 위치가 대각선
if graph[i][j] == 0 and graph[i][j-1] == 0 and graph[i-1][j] == 0:
dp[2][i][j] = dp[0][i-1][j-1] + dp[1][i-1][j-1] + dp[2][i-1][j-1]
# 현재 상태가 가로 / 세로
if graph[i][j] == 0:
dp[0][i][j] = dp[0][i][j - 1] + dp[2][i][j - 1] # 가로상태(가로->가로, 대각선->가로)
dp[1][i][j] = dp[1][i - 1][j] + dp[2][i - 1][j] # 세로상태(세로->세로, 대각선->세로)
res = 0
for i in range(3):
res += dp[i][n-1][n-1]
print(res)
DFS(시간초과)
import sys
def dfs(now):
global res
i, j, dir = now
# print(now)
if i == (n - 1) and j == (n - 1):
res += 1
return
# 대각선 이동
if (i + 1) < n and (j + 1) < n:
if g[i + 1][j] == 0 and g[i][j+1] == 0 and g[i+1][j+1] == 0:
dfs([i+1, j+1, 2])
# 가로 이동
if dir == 0 or dir == 2:
if (j + 1) < n:
if g[i][j + 1] == 0:
dfs([i, j + 1, 0])
# 세로 이동
if dir == 1 or dir == 2:
if (i + 1) < n:
if g[i + 1][j] == 0:
dfs([i + 1, j, 1])
return
n = int(sys.stdin.readline())
g = []
for _ in range(n): g.append(list(map(int, sys.stdin.readline().split())))
start = [0, 1, 0]
res = 0
dfs(start)
print(res)
BFS(시간초과)
import sys
from collections import deque
def check(r, c, flag):
if r == (n-1) and c == (n-1) and flag and graph[r][c] == 0: # 도착
global cnt
cnt += 1
return False
if r in range(n) and c in range(n) and graph[r][c] == 0: # 범위 체크, 가능성 확인
return True
else:
return False
def bfs():
queue = deque()
queue.append([0, 1, 0])
while queue:
i, j, dir = queue.popleft()
if dir == 0: # 가로
fir = [i, j+1, 0]
sec = [i+1, j+1, 2]
if check(fir[0], fir[1], True):
queue.append(fir)
if check(i+1, j, False) and check(i, j + 1, False) and check(sec[0], sec[1], True):
queue.append(sec)
elif dir == 1: # 세로
fir = [i + 1, j, 1]
sec = [i + 1, j + 1, 2]
if check(fir[0], fir[1], True):
queue.append(fir)
if check(i+1, j, False) and check(i, j + 1, False) and check(sec[0], sec[1], True):
queue.append(sec)
elif dir == 2: # 대각
fir = [i, j + 1, 0]
sec = [i + 1, j, 1]
thd = [i + 1, j + 1, 2]
if check(fir[0], fir[1], True):
queue.append(fir)
if check(sec[0], sec[1], True):
queue.append(sec)
if check(i+1, j, False) and check(i, j + 1, False) and check(thd[0], thd[1], True):
queue.append(thd)
return
n = int(sys.stdin.readline())
graph = []
for _ in range(n):
graph.append(list(map(int, sys.stdin.readline().split())))
cnt = 0
bfs()
print(cnt)
풀이
- 조건에 따라 입력받은 후 방향, 좌표에 따른 이동방식을 저장하기 위한 3차원 리스트(dp)를 만든다.
- 일괄적으로 가로로 이동이 가능한 케이스가 있기 때문에 for문을 사용해 맨 위의 열을 초기화한다.
- 이후, 현재 dp 리스트의 맨 처음 인덱스값에 따라 진행방향을 맞추어 나간다.
- 예를들어, dp[1][3][2]의 경우, 선발점이 graph[3][2]이고, 현재 세로방향으로 위치한다는 것을 의미한다.
- 이렇게 이중 for문을 실행하면서, 해당 인덱스의 graph값이 0인 경우 이동이 가능하기 때문에 앞선 방향으로부터 메모이제이션을 진행한다.
- 현재 위치에서 각각 가로, 세로, 대각선의 케이스를 전부 조건에 맞추어 구해나간 후, 마지막에는 해당 위치에 도달했을 때 가로, 세로, 대각선인 상태의 경우의 수를 전부 더한 다음 값을 출력한다.
알게된 점
- 처음 완전탐색을 사용해 BFS로 풀어보려 했지만 TLE
- 이후 DFS를 사용해 진행하려고 했지만 TLE
- 찾아보니까 파이썬은.... DFS, BFS로는 1초 안에 풀 수가 없는 듯 했다.
- 그래서 결국 DP로 풀이하는 방식을 참고했고, 아래 링크를 참고해서 풀 수 있었다.
- 처음에는 맨 위의 row를 전부 1로 초기화하는 이유를 몰랐지만, 가로, 세로의 경우에는 각각 오른쪽 아래로 진행한다는 것에 착안해 미리 선언했다는 것을 이해할 수 있었다.
- 정답률에 혹해서 풀었지만 되게.. 억까를 많이 당한듯한 문제였다.
참고 사이트
- DP 풀이 참고 : https://backtony.github.io/algorithm/2021-03-02-algorithm-boj-class4-44/
(Python) 백준 17070번 파이프 옮기기1 - class 4
[문제 링크]
backtony.github.io