ps | |
---|---|
링크 | acmicpc.net/… |
출처 | BOJ |
문제 번호 | 19238 |
문제명 | 스타트 택시 |
레벨 | 골드 4 |
분류 |
BFS |
시간복잡도 | O(m*n^2) |
인풋사이즈 | n<=20, m<=400 |
사용한 언어 | Python |
제출기록 | 32208KB / 296ms |
최고기록 | 172ms |
해결날짜 | 2020/12/16 |
"""Solution code for "BOJ 19238. 스타트 택시".
- Problem link: https://www.acmicpc.net/problem/19238
- Solution link: http://www.teferi.net/ps/problems/boj/19238
"""
import collections
from typing import Callable, Generator, Iterable, List, Optional, Sequence, Tuple, TypeVar
T = TypeVar('T')
CellType = TypeVar('CellType')
PosType = Tuple[int, int]
INF = float('inf')
def bfs(start: T,
get_next: Callable[[T], Iterable[T]]) -> Generator[T, None, None]:
"""Yields (node, distance) pairs for nodes in BFS-order."""
yield (start, 0)
visited = set()
queue = collections.deque([(start, 0)])
while queue:
cur, dist = queue.popleft()
for next_ in get_next(cur):
if next_ not in visited:
visited.add(next_)
queue.append((next_, dist + 1))
yield (next_, dist + 1)
def min_dist_targets(source: T,
get_next: Callable[[T], Iterable[T]],
is_target: Callable[[T], bool],
limit: Optional[int]) -> Tuple[List[T], Optional[int]]:
targets = []
for pos, dist in bfs(source, get_next):
if limit and dist > limit:
break
if is_target(pos):
targets.append(pos)
limit = dist
return (targets, limit)
def get_neighbors_from_grid(
grid: Sequence[Sequence[CellType]],
empty: CellType
) -> Callable[[PosType], Generator[PosType, None, None]]:
"""Returns a generator that yields neighbor cells in the grid."""
row_count, col_count = len(grid), len(grid[0])
def get_neighbors(pos):
r, c = pos
for dr, dc in ((-1, 0), (0, -1), (0, 1), (1, 0)):
nr, nc = r + dr, c + dc
if (0 <= nr < row_count
and 0 <= nc < col_count
and grid[nr][nc] == empty):
yield (nr, nc)
return get_neighbors
def main():
N, M, fuel = [int(x) for x in input().split()]
grid = []
for _ in range(N):
grid.append([int(x) for x in input().split()])
cur_row, cur_col = [int(x) for x in input().split()]
passengers = {}
for _ in range(M):
r1, c1, r2, c2 = [int(x) for x in input().split()]
passengers[(r1 - 1, c1 - 1)] = ((r1 - 1, c1 - 1), (r2 - 1, c2 - 1))
get_next_fn = get_neighbors_from_grid(grid, empty=0)
source = (cur_row - 1, cur_col - 1)
for _ in range(M):
targets, dist = min_dist_targets(
source, get_next_fn, lambda pos: pos in passengers, fuel)
if not targets:
print(-1)
break
fuel -= dist
pos = min(targets)
source, sink = passengers[pos]
del passengers[pos]
targets, dist = min_dist_targets(
source, get_next_fn, lambda pos: pos == sink, fuel)
if not targets:
print(-1)
break
fuel += dist
source = sink
else:
print(fuel)
if __name__ == '__main__':
main()