삼성 기출 24년 하반기 오전 | 미지의 공간 탈출
실제 현장에서 문제 보자마자 와 구현어렵겠군.. 생각하고 끝내 풀지 못하고 나온 문제이다...
그래도 다시 풀면서 침착하게 설계하니, 5시간 정도만에 풀었다.
빡구현인데, 하나 어긋나기 굉장히 쉬워서 테스트케이스 걸리는거 하나하나 확인하고나서야 풀었다.
문제 상 시간의 벽에서 움직임을 하나하나 제 대 로 설정하는게 쉽진 않닿ㅎ
📌문제
GOLD2 / 구현 / BFS
https://www.codetree.ai/ko/frequent-problems/problems/escape-unknown-space/description
삼성 코딩테스트 기출 문제 설명: 미지의 공간 탈출 | 코드트리
삼성전자 코딩테스트 기출 문제 미지의 공간 탈출의 상세 설명입니다. 문제 요구사항을 정확히 파악하고 효율적인 알고리즘을 설계해보세요.
www.codetree.ai
📌문제 분석 및 설계
아래와 같은 요소들로 설계를 했다.
아마 해당 문제를 푼 여러 코드들이 다 복잡할 것이고, 내것도 그렇다..
남의 코드 해석하는 것도 어려우니 집중해야할 바는 [산을 어떻게 셋팅하냐]만 봐도 될 것 같다.
산에서 이동하는 것 또한 하드코딩 방식밖에 없으니.. 깊이 보지 않아도 될듯하다 !
지금부터 나는 시간의 벽을 산이라고 명명하겠다.
1. 위 그림처럼 산을 셋팅.
- 1-1 셋팅시 2를 발견하면 출발점으로 정의
2. 반복문을 통해 grid 탐색하며 최종 출구와 바닥상에서 산의 첫 꼭짓점 찾기.
3. grid에서 산크기+1 만큼씩 탐색하며(산 한 면 크기가 3x3이면 4x4크기를 탐색), 산과 바닥을 연결하는 좌표 찾기
- 3-1 동/서/남/북 별로 case나눠서 산위에서의 좌표 계산
4. 산과 grid에서 bfs 함수 작성
- 4-1 산에서 이동할때 '윗면 ↔ 동/서/남/북' 과 '서↔북' 이동 조건부로 구현
5. 이상 현상 함수구현
6. 메인함수 구현
- 6-1 산에서 grid로 가는 부분 못찾으면 -1 출력
- 6-2 아니면 산에서 탈출구가는 경로와 시간 계산 후 한번에 이동
- 6-3 해당시간동안 이상현상 확산해서 만약 탈출구를 가린다면 -1
- 6-4 아니면 grid상에서 최종 탈출구로 가는 경로와 시간 계산
- 6-5 해당 시간동안 이상현상 확산시키며 만약 확산경로와 최종 탈출구로 가능 경로와 겹친다면, 해당 시간에서 멈추고 다시 bfs 탐색
📌소스 코드
import sys
from collections import deque
sys.stdin = open("./input.txt")
input = sys.stdin.readline
dxs,dys=[0,0,1,-1],[1,-1,0,0] #동서남북
n,m,f=map(int,input().split()) #공간한변길이, 시간의벽한변길이, 이상현상 개수
grid=[list(map(int,input().split())) for _ in range(n)]
startx,starty=None,None
#산 셋팅
mountain=[[-1]*(m*4) for _ in range(2*m)]
for i in range(5):
if i==0: #동
for j in range(m):
mountain[m+j][2*m:3*m]=list(map(int,input().split()))
elif i==1: #서
for j in range(m):
mountain[m+j][:m]=list(map(int,input().split()))
elif i==2: #남
for j in range(m):
mountain[m+j][m:2*m]=list(map(int,input().split()))
elif i==3: #북
for j in range(m):
mountain[m+j][3*m:]=list(map(int,input().split()))
else:
for j in range(m):
mountain[j][m:2*m]=list(map(int,input().split()))
if 2 in mountain[j][m:2*m]: #출발지점 찾기
startx,starty=j,m+mountain[j][m:2*m].index(2)
fire=[]
for i in range(f):
fire.append(list(map(int,input().split())))
grid[fire[i][0]][fire[i][1]]=-1
#산이 바닥에서 맞물리는 첫 모서리 위치와 출구 좌표찾기
endx,endy,mountain_x,mountain_y=None,None,None,None
for i in range(n):
for j in range(n):
if grid[i][j]==4:
endx,endy=i,j
elif grid[i][j]==3 and mountain_y==None:
mountain_x,mountain_y=i,j
#산,바닥 상 산에서의 탈출구 좌표
ingridx,ingridy=2*m-1,None #3차원 상에 바닥으로 가는 탈출구 위치
for i in range(m+2):
if 0 in grid[mountain_x-1+i][mountain_y-1:mountain_y+m+1]:
temp=grid[mountain_x-1+i][mountain_y-1:mountain_y+m+1].index(0)
outMountainx,outMountainy=mountain_x-1+i,mountain_y-1+temp #2차원 평면 상 산 탈출구
if temp==0: #1
ingridy=i-1
elif temp==m+1: #0
ingridy=2*m+(m-i)
elif 0<temp<m+2 and i==0: #3
ingridy=3*m+(m-temp)
else: #2
ingridy=m+temp-1
break
def bfs(mountainis,startx,starty,endx,endy):
if mountainis:
visited=[[0]*(m*4) for _ in range(2*m)]
pq=deque([(startx,starty)])
visited[startx][starty]=1
while pq:
x,y=pq.popleft()
if (x,y)==(endx,endy):
return visited[x][y],visited
for dx,dy in zip(dxs,dys):
nx,ny=x+dx,y+dy
if 0<=x<m:
if nx<0:
ny=3*m+(2*m-ny)-1 ##
nx=m
elif ny<m:
ny=nx
nx=m
elif ny>=2*m:
ny=2*m+(m-nx-1)
nx=m
else:
if ny>=4*m:
ny=0
elif ny<0:
ny=(4*m)-1
if nx<m:
if ny<m:
nx=ny
ny=m
elif 2*m<=ny<3*m:
nx=m-1-(2*m-ny)
ny=2*m-1
elif ny>=3*m:
nx=0
ny=m+(m-1-(3*m-ny))
if 0<=nx<(2*m) and 0<=ny<(m*4) and mountain[nx][ny]==0 and visited[nx][ny]==0:
pq.append((nx,ny))
visited[nx][ny]=visited[x][y]+1
return -1,None
else:
visited=[[0]*n for _ in range(n)]
pq=deque([(startx,starty)])
visited[startx][starty]=1
while pq:
x,y=pq.popleft()
if (x,y)==(endx,endy):
return visited[x][y],visited
for dx,dy in zip(dxs,dys):
nx,ny=x+dx,y+dy
if 0<=nx<n and 0<=ny<n and (grid[nx][ny]==0 or grid[nx][ny]==4) and visited[nx][ny]==0:
pq.append((nx,ny))
visited[nx][ny]=visited[x][y]+1
return -1,None
def move_fire(day):
check=False
for i,(r,c,d,v) in enumerate(fire):
if day>0 and day%v==0:
nx,ny=r+dxs[d],c+dys[d]
if 0<=nx<n and 0<=ny<n and (nx,ny)!=(endx,endy) and grid[nx][ny]!=1:
grid[nx][ny]=-1
fire[i]=[nx,ny,d,v]
if (nx,ny)==(outMountainx,outMountainy):
check=True
return check
############################################################################
result=0
days=0
stop=False
if ingridy==None: #6-1
print(-1)
else:
t1,_=bfs(True,startx,starty,ingridx,ingridy) #6-2
if t1==-1:
print(-1)
else:
for d in range(t1): #6-3
if move_fire(d):
stop=True
print(-1)
if stop==False:
move_fire(t1)
days=t1
loop=True
while loop: #6-4
out=False
t2,visitedd=bfs(False,outMountainx,outMountainy,endx,endy)
middle=0
if t2==-1:
loop=False
else:
for d in range(middle+t2):
move_fire(days+1+d)
for x,y,_,_ in fire:
if visitedd[x][y]!=0: #6-5
grid[x][y]
out=True
if out==True:
middle+=d
break
if out:
continue
loop=False
if t2==-1:
print(-1)
else:
print(days+t2-1)