19238번
BFS+시뮬레이션 문제이다.
우선 문제를 간략히 정리해보자.
문제를 접했을 때, 생각보다 구현방법이 쉽게 나왔다. 하지만 금방 풀지는 못했다. 문제를 풀면서 자잘한 디테일들이 좀 많은 문제였다.
시나리오를 적어보겠다.
시나리오
시나리오 자체는 상당히 간단하다. 탐색을 두번만 하면 되는것이다. 이제 한번 코드를 짜보겠다.
우선 그래프상에 승객위치와 목적지를 설정하자.
for _ in range(n):
graph.append(list(map(int, input().split())))
start_x,start_y=map(int, input().split()) #운전 시작 칸
# 주어진 좌표의 그래프는 시작점이 1부터 이므로 -1을 해준다.
start_x, start_y = start_x-1, start_y-1
for i in range(m):
#승객의 위치, 목적지에 대한 좌표를 입력받는다.
pass_fir_x,pass_fir_y,pass_end_x,pass_end_y=map(int, input().split())
graph[pass_fir_x-1][pass_fir_y-1]=(pass_end_x-1,pass_end_y-1) #승객의 위치에 목적지 좌표 삽입
위와 같이 승객의 위치에 특정 수를 넣는것이 아닌, 목적지에 대한 좌표를 넣어서 해당 승객의 목적지를 별도의 탐색없이 알 수 있도록 했다.
#택시가 승객을 태우러 가는 과정
def bfs(x,y,dist):
q=deque()
visited=[[0 for _ in range(n)]for _ in range(n)]
q.append([x,y,dist])
visited[x][y]=1
#가장 가까운 승객을 담는 리스트
passanger=[]
max_dist=sys.maxsize
while q:
x,y,dist=q.popleft()
#현재 거리가 max_dist 보다 크면 continue
if dist>max_dist:
continue
# x,y가 승객좌표일때
if graph[x][y]!=0 and graph[x][y]!=1: #승객의 위치에는 1과 0이 아니라 목적지 좌표가 들어있음.
passanger.append([dist,x,y])
max_dist=dist
for i in range(4):
nx=x+dx[i]
ny=y+dy[i]
if 0<=nx<n and 0<=ny<n and graph[nx][ny]!=1:
if visited[nx][ny]==0:
q.append([nx,ny,dist+1])
visited[nx][ny]=1
if passanger:
#정렬을 통해 거리가 짧고, 행이 위에있고, 열이 왼쪽에 있는 것을 정렬
return sorted(passanger)
else:
return False
위에서 말했듯이, 연료사용량은 결국 이동거리이다. 따라서 이동거리를 고려해서 bfs 탐색을 하고, 가장 가까운 승객들을 passanger 리스트에 담아서 거리>x좌표>y좌표 의 우선순위를 고려하여 정렬했다.
while m>0:
res=bfs(start_x,start_y,0)
#bfs 결과가 false면 승객을 못태운것이므로 -1
if not res:
print(-1)
exit()
near_pass=res[0]
use_fuel=near_pass[0]
x=near_pass[1]
y=near_pass[2]
fuel=fuel-use_fuel
#연료가 0보다 적으면 실패
if fuel<0:
print(-1)
exit()
#목적지 좌표 설정
pass_end_x, pass_end_y = (graph[x][y])[0], (graph[x][y])[1]
graph[x][y]=0 #승객 위치는 빈칸으로 변경
# 승객의 목적지를 가는 과정
def move(x,y, endx,endy,dist):
q=deque()
visited=[[0 for _ in range(n)]for _ in range(n)]
q.append([x,y,dist])
visited[x][y]=1
while q:
x,y,dist=q.popleft()
if (x,y)==(endx,endy):
return dist
for i in range(4):
nx=x+dx[i]
ny=y+dy[i]
if 0<=nx<n and 0<=ny<n and graph[nx][ny]!=1:
if visited[nx][ny]==0:
q.append([nx,ny,dist+1])
visited[nx][ny]=1
승객이 목적지로 향하는 탐색은 간단하다. 시작점, 도착점이 정해진 bfs 탐색이므로 일단 bfs 탐색하듯이 해주면 된다.
반환값으로 거리를 반환해주면 된다.
use_fuel=move(x,y,pass_end_x,pass_end_y,0)
#move의 결과가 false면 목적지를 도달 못했으므로 실패
if not use_fuel:
print(-1)
exit()
fuel=fuel-use_fuel
if fuel<0:
print(-1)
exit()
fuel=fuel+2*use_fuel
start_x=pass_end_x
start_y=pass_end_y
m-=1
import sys
input=sys.stdin.readline
from collections import deque
n,m,fuel=map(int, input().split()) #격자 크기, 승객 수, 연료량
graph=[]
for _ in range(n):
graph.append(list(map(int, input().split())))
start_x,start_y=map(int, input().split()) #운전 시작 칸
# 주어진 좌표의 그래프는 1부터 이므로 -1을 해준다.
start_x, start_y = start_x-1, start_y-1
for i in range(m):
pass_fir_x,pass_fir_y,pass_end_x,pass_end_y=map(int, input().split())
graph[pass_fir_x-1][pass_fir_y-1]=(pass_end_x-1,pass_end_y-1) #승객의 위치에 목적지 좌표 삽입
dx=[-1,1,0,0]
dy=[0,0,-1,1]
#택시가 승객을 태우러 가는 과정
def bfs(x,y,dist):
q=deque()
visited=[[0 for _ in range(n)]for _ in range(n)]
q.append([x,y,dist])
visited[x][y]=1
passanger=[]
max_dist=sys.maxsize
while q:
x,y,dist=q.popleft()
if dist>max_dist:
continue
# x,y가 승객좌표일때
if graph[x][y]!=0 and graph[x][y]!=1:
passanger.append([dist,x,y])
max_dist=dist
for i in range(4):
nx=x+dx[i]
ny=y+dy[i]
if 0<=nx<n and 0<=ny<n and graph[nx][ny]!=1:
if visited[nx][ny]==0:
q.append([nx,ny,dist+1])
visited[nx][ny]=1
if passanger:
return sorted(passanger)
else:
return False
# 승객의 목적지를 가는 과정
def move(x,y, endx,endy,dist):
q=deque()
visited=[[0 for _ in range(n)]for _ in range(n)]
q.append([x,y,dist])
visited[x][y]=1
while q:
x,y,dist=q.popleft()
if (x,y)==(endx,endy):
return dist
for i in range(4):
nx=x+dx[i]
ny=y+dy[i]
if 0<=nx<n and 0<=ny<n and graph[nx][ny]!=1:
if visited[nx][ny]==0:
q.append([nx,ny,dist+1])
visited[nx][ny]=1
while m>0:
res=bfs(start_x,start_y,0)
#bfs 결과가 false면 승객을 못태운것이므로 -1
if not res:
print(-1)
exit()
near_pass=res[0]
use_fuel=near_pass[0]
x=near_pass[1]
y=near_pass[2]
fuel=fuel-use_fuel
#연료가 0보다 적으면 실패
if fuel<0:
print(-1)
exit()
#목적지 좌표 설정
pass_end_x, pass_end_y = (graph[x][y])[0], (graph[x][y])[1]
graph[x][y]=0 #승객 위치는 빈칸으로 변경
use_fuel=move(x,y,pass_end_x,pass_end_y,0)
#move의 결과가 false면 목적지를 도달 못했으므로 실패
if not use_fuel:
print(-1)
exit()
fuel=fuel-use_fuel
if fuel<0:
print(-1)
exit()
fuel=fuel+2*use_fuel
start_x=pass_end_x
start_y=pass_end_y
m-=1
print(fuel)