#16197번 두 동전 https://www.acmicpc.net/problem/16197
16197번: 두 동전
N×M 크기의 보드와 4개의 버튼으로 이루어진 게임이 있다. 보드는 1×1크기의 정사각형 칸으로 나누어져 있고, 각각의 칸은 비어있거나, 벽이다. 두 개의 빈 칸에는 동전이 하나씩 놓여져 있고,
www.acmicpc.net
열심히 코드를 짰다.
DFS로 도전했다가 재귀 깊이 에러가 나서 (에초에 종료조건이 없었다.)
BFS로 변경했다. (최단거리 문제는 너비우선 탐색이 좋다.)
틀린코드 1
r, c = map(int, input().split())
graph = []
coins = []
for i in range(r):
row = input()
tmp = []
for j in range(c):
if row[j] == "o":
tmp.append(True)
coins.append([i, j])
elif row[j] == ".":
tmp.append(True)
else: # row[j] == "#"
tmp.append(False)
graph.append(tmp)
dr = [1, -1, 0, 0]
dc = [0, 0, 1, -1]
que = []
def solve(init):
que.append(init)
while que:
coins = que.pop(0)
# print(coins)
if coins[2] > 10:
return -1
for i in range(4):
# 이동
nr1 = coins[0][0] + dr[i]
nc1 = coins[0][1] + dc[i]
nr2 = coins[1][0] + dr[i]
nc2 = coins[1][1] + dc[i]
cnt = coins[2]
# 검증
bool1 = 0 <= nr1 < r and 0 <= nc1 < c
bool2 = 0 <= nr2 < r and 0 <= nc2 < c
# print(nr1, nc1, bool1, nr2, nc2, bool2)
# 이동한 위치가 벽일 경우에 보정
if bool1 and not graph[nr1][nc1]:
nr1, nc1 = coins[0][0], coins[0][1]
if bool2 and not graph[nr2][nc2]:
nr2, nc2 = coins[1][0], coins[1][1]
if bool1 and bool2: # 둘 다 안떨어졌을 때
que.append([[nr1, nc1], [nr2, nc2], cnt+1])
elif not bool1 and not bool2: # 둘 다 떨어졌을 때
continue
else: # 하나만 떨어졌을 때
return cnt+1
# exit()
print(solve(coins+[0]))
버튼을 누른 횟수가 10이 넘어가면 종료하도록 했는데
문제는 10이 넘어갈 때까지 연산 횟수가 너무 많다는 점이다.
그래서 방문 기록을 해야겠다는 생각을 했다.
근데 문제는 동전이 두개라는 점이다.
틀린코드 2
r, c = map(int, input().split())
graph = []
coins = []
for i in range(r):
row = input()
tmp = []
for j in range(c):
if row[j] == "o":
tmp.append(True)
coins.append([i, j])
elif row[j] == ".":
tmp.append(True)
else: # row[j] == "#"
tmp.append(False)
graph.append(tmp)
dr = [1, -1, 0, 0]
dc = [0, 0, 1, -1]
visited = [[[[False]*c for _ in range(r)]
for __ in range(c)] for ___ in range(r)]
que = []
def solve(init):
que.append(init)
visited[init[0][0]][init[0][1]][init[1][0]][init[1][1]] = True
while que:
coins = que.pop(0)
# print(coins)
if coins[2] > 10:
return -1
for i in range(4):
# 이동
nr1 = coins[0][0] + dr[i]
nc1 = coins[0][1] + dc[i]
nr2 = coins[1][0] + dr[i]
nc2 = coins[1][1] + dc[i]
cnt = coins[2]
# 검증
bool1 = 0 <= nr1 < r and 0 <= nc1 < c
bool2 = 0 <= nr2 < r and 0 <= nc2 < c
# print(nr1, nc1, bool1, nr2, nc2, bool2)
# 이동한 위치가 벽일 경우에 보정
if bool1 and not graph[nr1][nc1]:
nr1, nc1 = coins[0][0], coins[0][1]
if bool2 and not graph[nr2][nc2]:
nr2, nc2 = coins[1][0], coins[1][1]
if bool1 and bool2: # 둘 다 안떨어졌을 때
if not visited[nr1][nc1][nr2][nc2]:
visited[nr1][nc1][nr2][nc2] = True
que.append([[nr1, nc1], [nr2, nc2], cnt+1])
elif not bool1 and not bool2: # 둘 다 떨어졌을 때
continue
else: # 하나만 떨어졌을 때
return cnt+1
# exit()
return -1
print(solve(coins+[0]))
그렇게 수정한 코드이다. 2개의 동전이 특정 위치에 각각 존재했던 경우를 기록한다고 보면 된다. (4차원 리스트)
근데 틀렸다. (왜..?)
정확한 이유는 짚기 어렵지만
논리 순서가 잘못됐다고 판단했다.
1. 둘 다 떨어졌을 때 ( 두개의 코인이 모두 그래프의 범위를 벗어날 때)
2. 하나만 떨어졌을 때 (문제가 요구하는 상황)
3. 벽을 만났을 때
4. 둘 다 안떨어졌을 때
정답코드
r, c = map(int, input().split())
graph = []
coins = []
for i in range(r):
row = input()
tmp = []
for j in range(c):
if row[j] == "o":
tmp.append(True)
coins.append([i, j])
elif row[j] == ".":
tmp.append(True)
else: # row[j] == "#"
tmp.append(False)
graph.append(tmp)
dr = [1, -1, 0, 0]
dc = [0, 0, 1, -1]
visited = [[[[False]*c for _ in range(r)]
for __ in range(c)] for ___ in range(r)]
que = []
def visitable(x, y):
return 0 <= x < r and 0 <= y < c
def solve(init):
que.append(init)
visited[init[0][0]][init[0][1]][init[1][0]][init[1][1]] = True
while que:
coins = que.pop(0)
# print(coins)
if coins[2] > 10:
break
for i in range(4):
# 이동
nr1 = coins[0][0] + dr[i]
nc1 = coins[0][1] + dc[i]
nr2 = coins[1][0] + dr[i]
nc2 = coins[1][1] + dc[i]
cnt = coins[2]
# 둘 다 떨어졌을 때
if not visitable(nr1, nc1) and not visitable(nr2, nc2):
continue
# 하나만 떨어졌을 때
if (not visitable(nr1, nc1) and visitable(nr2, nc2)) or (visitable(nr1, nc1) and not visitable(nr2, nc2)):
return cnt
# 벽을 만났을 때
if not graph[nr1][nc1]:
nr1, nc1 = coins[0][0], coins[0][1]
if not graph[nr2][nc2]:
nr2, nc2 = coins[1][0], coins[1][1]
# 둘 다 안떨어졌을 때
if not visited[nr1][nc1][nr2][nc2]:
visited[nr1][nc1][nr2][nc2] = True
que.append([[nr1, nc1], [nr2, nc2], cnt+1])
return -1
print(solve(coins+[1]))
탈락되는 경우의 수가 가장 많은 경우를 우선으로 진행하는게 맞다고 느꼈다.
게다가, 둘 다 떨어진 경우는 그래프의 범위를 벗어나는 경우이다. 즉 틀린코드처럼 벽을 만나는 경우를 우선 처리할 경우에 index error를 고려한 코드를 추가로 작성해야한다.
-> 논리적 구조가 복잡해진다.
깨달은 바가 있는 문제였다.
'Algorithm > acmicpc.net' 카테고리의 다른 글
파이썬 시간초과의 늪 (골드 4) (0) | 2022.02.17 |
---|---|
이젠 스도쿠 천재 (골드4) (0) | 2022.02.15 |
아니.. 난 아직 멍청하다 (dfs) (0) | 2022.02.13 |
때론 머리를 비우기도 하기 (실버2) (0) | 2022.02.13 |
뇌가 돌아오는중 (그리디, 브루트포스) (0) | 2022.02.13 |