[λ°±μ€€/python] 19238번 : μŠ€νƒ€νŠΈ νƒμ‹œ

2021. 9. 22. 02:53

문제

μŠ€νƒ€νŠΈλ§ν¬κ°€ "μŠ€νƒ€νŠΈ νƒμ‹œ"λΌλŠ” μ΄λ¦„μ˜ νƒμ‹œ 사업을 μ‹œμž‘ν–ˆλ‹€. μŠ€νƒ€νŠΈ νƒμ‹œλŠ” νŠΉμ΄ν•˜κ²Œλ„ μ†λ‹˜μ„ λ„μ°©μ§€λ‘œ 데렀닀쀄 λ•Œλ§ˆλ‹€ μ—°λ£Œκ°€ μΆ©μ „λ˜κ³ , μ—°λ£Œκ°€ λ°”λ‹₯λ‚˜λ©΄ κ·Έ λ‚ μ˜ 업무가 λλ‚œλ‹€.

νƒμ‹œ 기사 μ΅œλ°±μ€€μ€ 였늘 Mλͺ…μ˜ μŠΉκ°μ„ νƒœμš°λŠ” 것이 λͺ©ν‘œμ΄λ‹€. 백쀀이 ν™œλ™ν•  μ˜μ—­μ€ N×N 크기의 격자둜 λ‚˜νƒ€λ‚Ό 수 있고, 각 칸은 λΉ„μ–΄ μžˆκ±°λ‚˜ 벽이 놓여 μžˆλ‹€. νƒμ‹œκ°€ λΉˆμΉΈμ— μžˆμ„ λ•Œ, μƒν•˜μ’Œμš°λ‘œ μΈμ ‘ν•œ 빈칸 쀑 ν•˜λ‚˜λ‘œ 이동할 수 μžˆλ‹€. μ•Œκ³ λ¦¬μ¦˜ κ²½λ ₯이 λ§Žμ€ λ°±μ€€μ€ νŠΉμ • μœ„μΉ˜λ‘œ 이동할 λ•Œ 항상 μ΅œλ‹¨κ²½λ‘œλ‘œλ§Œ μ΄λ™ν•œλ‹€.

Mλͺ…μ˜ μŠΉκ°μ€ 빈칸 쀑 ν•˜λ‚˜μ— μ„œ 있으며, λ‹€λ₯Έ 빈칸 쀑 ν•˜λ‚˜λ‘œ μ΄λ™ν•˜λ €κ³  ν•œλ‹€. μ—¬λŸ¬ 승객이 같이 νƒ‘μŠΉν•˜λŠ” κ²½μš°λŠ” μ—†λ‹€. λ”°λΌμ„œ 백쀀은 ν•œ μŠΉκ°μ„ νƒœμ›Œ λͺ©μ μ§€λ‘œ μ΄λ™μ‹œν‚€λŠ” 일을 M번 λ°˜λ³΅ν•΄μ•Ό ν•œλ‹€. 각 μŠΉκ°μ€ 슀슀둜 움직이지 μ•ŠμœΌλ©°, μΆœλ°œμ§€μ—μ„œλ§Œ νƒμ‹œμ— νƒˆ 수 있고, λͺ©μ μ§€μ—μ„œλ§Œ νƒμ‹œμ—μ„œ 내릴 수 μžˆλ‹€.

백쀀이 νƒœμšΈ μŠΉκ°μ„ κ³ λ₯Ό λ•ŒλŠ” ν˜„μž¬ μœ„μΉ˜μ—μ„œ μ΅œλ‹¨κ±°λ¦¬κ°€ κ°€μž₯ 짧은 μŠΉκ°μ„ κ³ λ₯Έλ‹€. 그런 승객이 μ—¬λŸ¬ λͺ…이면 그쀑 ν–‰ λ²ˆν˜Έκ°€ κ°€μž₯ μž‘μ€ μŠΉκ°μ„, 그런 μŠΉκ°λ„ μ—¬λŸ¬ λͺ…이면 그쀑 μ—΄ λ²ˆν˜Έκ°€ κ°€μž₯ μž‘μ€ μŠΉκ°μ„ κ³ λ₯Έλ‹€. νƒμ‹œμ™€ 승객이 같은 μœ„μΉ˜μ— μ„œ 있으면 κ·Έ μŠΉκ°κΉŒμ§€μ˜ μ΅œλ‹¨κ±°λ¦¬λŠ” 0이닀. μ—°λ£ŒλŠ” ν•œ μΉΈ 이동할 λ•Œλ§ˆλ‹€ 1만큼 μ†Œλͺ¨λœλ‹€. ν•œ μŠΉκ°μ„ λͺ©μ μ§€λ‘œ μ„±κ³΅μ μœΌλ‘œ μ΄λ™μ‹œν‚€λ©΄, κ·Έ μŠΉκ°μ„ νƒœμ›Œ μ΄λ™ν•˜λ©΄μ„œ μ†Œλͺ¨ν•œ μ—°λ£Œ μ–‘μ˜ 두 λ°°κ°€ μΆ©μ „λœλ‹€. μ΄λ™ν•˜λŠ” 도쀑에 μ—°λ£Œκ°€ λ°”λ‹₯λ‚˜λ©΄ 이동에 μ‹€νŒ¨ν•˜κ³ , κ·Έ λ‚ μ˜ 업무가 λλ‚œλ‹€. μŠΉκ°μ„ λͺ©μ μ§€λ‘œ μ΄λ™μ‹œν‚¨ λ™μ‹œμ— μ—°λ£Œκ°€ λ°”λ‹₯λ‚˜λŠ” κ²½μš°λŠ” μ‹€νŒ¨ν•œ κ²ƒμœΌλ‘œ κ°„μ£Όν•˜μ§€ μ•ŠλŠ”λ‹€.

 

λͺ¨λ“  μŠΉκ°μ„ μ„±κ³΅μ μœΌλ‘œ 데렀닀쀄 수 μžˆλŠ”μ§€ μ•Œμ•„λ‚΄κ³ , 데렀닀쀄 수 μžˆμ„ 경우 μ΅œμ’…μ μœΌλ‘œ λ‚¨λŠ” μ—°λ£Œμ˜ 양을 좜λ ₯ν•˜λŠ” ν”„λ‘œκ·Έλž¨μ„ μž‘μ„±ν•˜μ‹œμ˜€.

 

μž…λ ₯

첫 쀄에 N, M, 그리고 초기 μ—°λ£Œμ˜ 양이 주어진닀. (2 ≤ N ≤ 20, 1 ≤ M ≤ N2, 1 ≤ 초기 μ—°λ£Œ ≤ 500,000) μ—°λ£ŒλŠ” λ¬΄ν•œνžˆ 많이 담을 수 있기 λ•Œλ¬Έμ—, 초기 μ—°λ£Œμ˜ 양을 λ„˜μ–΄μ„œ 좩전될 μˆ˜λ„ μžˆλ‹€.

λ‹€μŒ 쀄뢀터 N개의 쀄에 걸쳐 백쀀이 ν™œλ™ν•  μ˜μ—­μ˜ 지도가 주어진닀. 0은 빈칸, 1은 벽을 λ‚˜νƒ€λ‚Έλ‹€.

λ‹€μŒ μ€„μ—λŠ” 백쀀이 μš΄μ „μ„ μ‹œμž‘ν•˜λŠ” 칸의 ν–‰ λ²ˆν˜Έμ™€ μ—΄ λ²ˆν˜Έκ°€ 주어진닀. ν–‰κ³Ό μ—΄ λ²ˆν˜ΈλŠ” 1 이상 N μ΄ν•˜μ˜ μžμ—°μˆ˜μ΄κ³ , μš΄μ „μ„ μ‹œμž‘ν•˜λŠ” 칸은 λΉˆμΉΈμ΄λ‹€.

κ·Έλ‹€μŒ 쀄뢀터 M개의 쀄에 걸쳐 각 승객의 μΆœλ°œμ§€μ˜ ν–‰κ³Ό μ—΄ 번호, 그리고 λͺ©μ μ§€μ˜ ν–‰κ³Ό μ—΄ λ²ˆν˜Έκ°€ 주어진닀. λͺ¨λ“  μΆœλ°œμ§€μ™€ λͺ©μ μ§€λŠ” 빈칸이고, λͺ¨λ“  μΆœλ°œμ§€λŠ” μ„œλ‘œ λ‹€λ₯΄λ©°, 각 μ†λ‹˜μ˜ μΆœλ°œμ§€μ™€ λͺ©μ μ§€λŠ” λ‹€λ₯΄λ‹€.

 

좜λ ₯

λͺ¨λ“  μ†λ‹˜μ„ μ΄λ™μ‹œν‚€κ³  μ—°λ£Œλ₯Ό μΆ©μ „ν–ˆμ„ λ•Œ 남은 μ—°λ£Œμ˜ 양을 좜λ ₯ν•œλ‹€. 단, 이동 도쀑에 μ—°λ£Œκ°€ λ°”λ‹₯λ‚˜μ„œ λ‹€μŒ μΆœλ°œμ§€λ‚˜ λͺ©μ μ§€λ‘œ 이동할 수 μ—†μœΌλ©΄ -1을 좜λ ₯ν•œλ‹€. λͺ¨λ“  μ†λ‹˜μ„ μ΄λ™μ‹œν‚¬ 수 μ—†λŠ” κ²½μš°μ—λ„ -1을 좜λ ₯ν•œλ‹€.

 

μ •λ‹΅

import sys
input = sys.stdin.readline

# N, M, 초기 μ—°λ£Œ μ–‘ μž…λ ₯
N, M, fuel = map(int, input().split())

# ν™œλ™ μ˜μ—­ 지도 area μž…λ ₯
area = [[1 for _ in range(N+1)]]
for _ in range(N):
    area.append([1])
    area[-1].extend(list(map(int, input().split())))

# μš΄μ „μ„ μ‹œμž‘ν•˜λŠ” μΉΈ now μž…λ ₯
now = tuple(map(int, input().split()))

# 승객의 μΆœλ°œμ§€μ™€ λͺ©μ μ§€ μž…λ ₯
passenger = {}
for _ in range(M):
    a, b, c, d = map(int, input().split())
    passenger[(a, b)] = (c, d)

around = [(0,1), (1,0), (-1,0), (0,-1)]

take_a_taxi = False

while passenger:
    arrival, target = tuple(), set()
    visited, queue = set(), {now}
    move = 0
    
    while queue:
        candidate = set()
        for x, y in queue:
            if (0 <= x < N+1 and 0 <= y < N+1) and area[x][y] == 0:
                if take_a_taxi and (x, y) == passenger[now]:
                    del passenger[now]
                    arrival = (x, y)
                    break
                
                elif not take_a_taxi and (x, y) in passenger:
                    target.add((x, y))
                
                else:
                    for _x, _y in around:
                        if (x+_x, y+_y) not in visited:
                            candidate.add((x+_x, y+_y))
        
            visited.add((x, y))
            
        if arrival:
            take_a_taxi = False
            now = arrival
            fuel = fuel + move if fuel >= move else -1
            break

        if target:
            take_a_taxi = True
            now = sorted(target)[0]
            fuel -= move
            break
            
        if not candidate:
            fuel = -1
            break
        
        queue = candidate
        move += 1

    if fuel < 0:
        fuel = -1
        break

print(fuel)

# N, M, 초기 μ—°λ£Œ μ–‘ μž…λ ₯
N, M, fuel = map(int, input().split())

# ν™œλ™ μ˜μ—­ 지도 area μž…λ ₯
area = [[1 for _ in range(N+1)]]
for _ in range(N):
    area.append([1])
    area[-1].extend(list(map(int, input().split())))

# μš΄μ „μ„ μ‹œμž‘ν•˜λŠ” μΉΈ now μž…λ ₯
now = tuple(map(int, input().split()))

# 승객의 μΆœλ°œμ§€μ™€ λͺ©μ μ§€ μž…λ ₯
passenger = {}
for _ in range(M):
    a, b, c, d = map(int, input().split())
    passenger[(a, b)] = (c, d)

around = [(0,1), (1,0), (-1,0), (0,-1)]

take_a_taxi = False

while passenger:
    arrival, target = tuple(), set()
    visited, queue = set(), {now}
    move = 0
    
    while queue:
        candidate = set()

μž…λ ₯을 λ°›κ³  ν•„μš”ν•œ λ³€μˆ˜λ“€μ„ μƒμ„±ν•œλ‹€.

 

  • area : λ¬Έμ œμ—μ„œ 인덱슀 1λΆ€ν„° μ‹œμž‘ν•˜λ―€λ‘œ κ°€λ‘œ, μ„Έλ‘œ 첫쀄에 μ˜λ―Έμ—†λŠ” 1을 μΆ”κ°€ν•΄λ…Ό ν›„ μž…λ ₯λ°›λŠ”λ‹€.
  • passenger : 승객의 μΆœλ°œμ§€μ™€ λͺ©μ μ§€λŠ” μΆœλ°œμ§€ : λͺ©μ μ§€ ν˜•νƒœλ‘œ λ”•μ…”λ„ˆλ¦¬λ‘œ μ €μž₯ν•œλ‹€.
  • around : μƒν•˜μ’Œμš°λ‘œ 이동할 λ•Œ λ”ν•΄μ§€λŠ” μ’Œν‘œκ°’μ΄λ‹€.
  • take_a_taxi : νƒμ‹œμ— 승객이 μžˆλŠ”μ§€ μ—†λŠ”μ§€ μƒνƒœλ₯Ό λ‚˜νƒ€λ‚Έλ‹€.
  • arrival : νƒμ‹œμ— 탄 승객이 λͺ©μ μ§€μ— λ„μ°©ν–ˆμ„ λ•Œ λͺ©μ μ§€ μ’Œν‘œλ₯Ό μ €μž₯ν•œλ‹€.
  • target : 같은 μ΄λ™νšŸμˆ˜ μ•ˆμ—μ„œ 갈 수 μžˆλŠ” 승객의 μœ„μΉ˜λ₯Ό μ €μž₯ν•œλ‹€.
  • visited : 이미 λ°©λ¬Έν•œ μ’Œν‘œλŠ” λ°©λ¬Έν•˜μ§€ μ•ŠκΈ° μœ„ν•΄ λ°©λ¬Έν•œ μ’Œν‘œλ₯Ό μ €μž₯ν•΄λ†“λŠ”λ‹€.
  • queue : 이동해야할 곳을 μ €μž₯ν•œλ‹€.
  • move : μ΄λ™νšŸμˆ˜λ₯Ό μ˜λ―Έν•œλ‹€.
  • candidate : 같은 μ΄λ™νšŸμˆ˜λ‘œ 갈 수 μžˆλŠ” μ’Œν‘œλ“€μ„ μ €μž₯ν•œλ‹€.

 

for x, y in queue:
            if (0 <= x < N+1 and 0 <= y < N+1) and area[x][y] == 0:
                if take_a_taxi and (x, y) == passenger[now]:
                    del passenger[now]
                    arrival = (x, y)
                    break
                
                elif not take_a_taxi and (x, y) in passenger:
                    target.add((x, y))
                
                else:
                    for _x, _y in around:
                        if (x+_x, y+_y) not in visited:
                            candidate.add((x+_x, y+_y))
        
            visited.add((x, y))

queueμ—λŠ” 같은 μ΄λ™νšŸμˆ˜λ‘œ 갈 수 μžˆλŠ” μ’Œν‘œλ“€μ΄ λ“€μ–΄μžˆλ‹€.

queue에 μžˆλŠ” μ’Œν‘œλ₯Ό ν•˜λ‚˜μ”© λŒλ©΄μ„œ 인덱슀 λ²”μœ„ 내에 μžˆμœΌλ©΄μ„œ 벽이 아닐 λ•Œ

λ‹€μŒ 세가지 사항 쀑 λ§žλŠ” μƒν™©μ—μ„œ ν–‰λ™ν•œλ‹€.

  • νƒμ‹œμ— 승객이 있고 ν˜„μž¬ μœ„μΉ˜κ°€ λͺ©μ μ§€λΌλ©΄ ->
    • passengerμ—μ„œ ν•΄λ‹Ή μŠΉκ°μ„ μ‚­μ œν•œλ‹€.
    • arrival에 λͺ©μ μ§€ μ’Œν‘œλ₯Ό μ €μž₯ν•œλ‹€.
    • 더 이상 λ‹€λ₯Έ μ’Œν‘œλ₯Ό λ³Ό ν•„μš” μ—†μœΌλ―€λ‘œ for문을 λΉ μ Έλ‚˜μ˜¨λ‹€.
  • νƒμ‹œμ— 승객이 μ—†κ³  ν˜„μž¬ μœ„μΉ˜μ— 승객이 μžˆλ‹€λ©΄ ->
    • νƒœμšΈ 승객 후보 target에 ν˜„μž¬ μœ„μΉ˜λ₯Ό μ €μž₯ν•œλ‹€.
  • κ·Έ μ™Έ ->
    • μƒν•˜μ’Œμš°λ₯Ό λŒλ©΄μ„œ λ°©λ¬Έν•œ 적이 μ—†λŠ” μ’Œν‘œλ₯Ό candidate에 μ €μž₯ν•œλ‹€.

 

ν˜„μž¬ μœ„μΉ˜μ— λ°©λ¬Έν–ˆμŒμ„ ν‘œμ‹œν•˜κΈ° μœ„ν•΄ visited에 ν˜„μž¬ μœ„μΉ˜λ₯Ό μΆ”κ°€ν•œλ‹€.

 

        if arrival:
            take_a_taxi = False
            now = arrival
            fuel = fuel + move if fuel >= move else -1
            break

        if target:
            take_a_taxi = True
            now = sorted(target)[0]
            fuel -= move
            break
            
        if not candidate:
            fuel = -1
            break
        
        queue = candidate
        move += 1

ν˜„μž¬ 이동 횟수둜 갈 수 μžˆλŠ” μ’Œν‘œλ₯Ό λͺ¨λ‘ ν™•μΈν•œ ν›„ λ‹€μŒ 세가지 사항을 μ²΄ν¬ν•œλ‹€.

  • λͺ©μ μ§€μ— λ„μ°©ν–ˆλ‹€λ©΄ ->
    • 승객이 내림을 ν‘œμ‹œν•˜κΈ° μœ„ν•΄ take_a_taxiλ₯Ό False둜 λ°”κΎΌλ‹€.
    • now에 arrival을 μ €μž₯ν•˜μ—¬ ν˜„μœ„μΉ˜λ₯Ό κ°±μ‹ ν•œλ‹€.
    • μ—°λ£Œκ°€ 움직인 κ²ƒλ§ŒνΌ μžˆμ—ˆλ‹€λ©΄ μ›€μ§μΈλ§ŒνΌ 더해주고 μ•„λ‹ˆλ©΄ -1둜 λ°”κΎΌλ‹€.
  • νƒœμšΈ 승객 후보가 μžˆλ‹€λ©΄ ->
    • 승객이 νƒ”μŒμ„ ν‘œμ‹œν•˜κΈ° μœ„ν•΄ take_a_taxiλ₯Ό True둜 λ°”κΎΌλ‹€.
    • now에 νƒœμšΈ 승객 후보 쀑 선택 쑰건에 λ§žλŠ” 승객의 μœ„μΉ˜λ₯Ό μ €μž₯ν•˜μ—¬ ν˜„μœ„μΉ˜λ₯Ό κ°±μ‹ ν•œλ‹€.
    • μ—°λ£Œλ₯Ό μ›€μ§μΈλ§ŒνΌ λΉΌμ€€λ‹€.
  • λ‹€μŒμœΌλ‘œ 이동할 μ’Œν‘œκ°€ μ—†λ‹€λ©΄ ->
    • μ—°λ£Œλ₯Ό -1둜 λ°”κΏ” 더이상 갈 수 μ—†μŒμ„ ν‘œμ‹œν•œλ‹€.

 

μœ„ 세가지 사항에 λͺ¨λ‘ λ§žμ§€ μ•ŠλŠ”λ‹€λ©΄

queueλ₯Ό candidate둜 λ°”κΎΌ ν›„ move에 1을 더해 λ‹€μŒμœΌλ‘œ 움직인닀.

728x90

BELATED ARTICLES

more