We will find a way, we always have.

-interstellar

Problem Solving/λ°±μ€€

[λ°±μ€€] 15944번: 성곡

Redddy 2024. 11. 7. 21:48

πŸ”ˆ 문제

λ‹Ήμ—°ν•œ μ΄μ•ΌκΈ°μ§€λ§Œ, μ„±κ³΅μœΌλ‘œ κ°€λŠ” 길이 항상 ν‰νƒ„ν•˜μ§€λ§Œμ€ μ•Šλ‹€. μ˜¨κ°– μž₯애물이 κ°€λ“ν•˜κ³ , μž₯애물에 λ§‰ν˜€μ„œ 주저앉을 μˆ˜λ„ μžˆλ‹€. κ·Έλž˜μ„œ κ·Έ μž₯애물을 ν­νŒŒν•˜λ €κ³  ν•œλ‹€.
μ„±κ³΅μœΌλ‘œ κ°€λŠ” 길은 N×M격자 μœ„μ— 놓여 μžˆλ‹€. μ„±κ³΅μœΌλ‘œ κ°€λ €λ©΄ 맨 μ™Όμͺ½ μœ„ μΉΈμ—μ„œ μ‹œμž‘ν•˜μ—¬ μž₯애물이 μ—†λŠ” μƒν•˜μ’Œμš°λ‘œ μΈμ ‘ν•œ 칸을 λ°ŸμœΌλ©΄μ„œ 맨 였λ₯Έμͺ½ μ•„λž˜ 칸에 도착해야 ν•œλ‹€. ν•œ 번의 폭파 μž‘μ—…μœΌλ‘œ D×D 격자 내에 μžˆλŠ” λͺ¨λ“  μž₯애물을 없앨 수 μžˆλ‹€. ν•˜μ§€λ§Œ 세상에 κ³΅μ§œλŠ” μ—†λŠ” 법. 폭파 μž‘μ—…μ—λ„ 큰 힘이 λ“€κΈ° λ•Œλ¬Έμ—, μ„±κ³΅μœΌλ‘œ κ°€λ €λ©΄ μ΅œμ†Œ λͺ‡ 번의 폭파 μž‘μ—…μ΄ ν•„μš”ν•œμ§€ μ•Œκ³  μ‹Άλ‹€.

πŸ“μž…λ ₯

첫 번째 쀄에 격자의 ν–‰μ˜ 개수 N, μ—΄μ˜ 개수 M, 폭파의 λ²”μœ„ Dκ°€ 주어진닀(D ≤ N, M ≤ 500, 1 ≤ D ≤ 100).
κ·Έ λ‹€μŒ N개의 쀄에 격자의 각 행을 λ‚˜νƒ€λ‚΄λŠ” 길이 M의 λ¬Έμžμ—΄μ΄ 주어진닀. “.”은 μž₯애물이 μ—†λŠ” μΉΈ, “#”은 μž₯애물이 μžˆλŠ” 칸이닀. 좜발 지점과 μ„±κ³΅μ—λŠ” μž₯애물이 μ—†λ‹€.

 

πŸ“‘μΆœλ ₯

첫 번째 쀄에 폭파 μž‘μ—…μ˜ μ΅œμ†Œ 횟수λ₯Ό 좜λ ₯ν•œλ‹€.

 

🧐 λ¬Έμ œ μ ‘κ·Ό

 

N * M λ³΄λ“œμ—μ„œ (0, 0) μ—μ„œ μ‹œμž‘ν•˜μ—¬ (N - 1, M - 1) κΉŒμ§€ λ„λ‹¬ν•˜κΈ° μœ„ν•΄μ„œ μ΅œμ†Œ λͺ‡ 번 벽을 ν­νŒŒν•΄μ•Ό ν•˜λŠ”κ°€? λ₯Ό ꡬ해야 ν•˜λŠ” λ¬Έμ œμ΄λ‹€. 벽을 ν­νŒŒν•  λ•ŒλŠ” ν•œ 칸만 λΆ€μˆ  수 μžˆλŠ”κ²Œ μ•„λ‹ˆλΌ D * D λ²”μœ„λ₯Ό ν­νŒŒμ‹œν‚¨λ‹€.

 

'κ·Έλž˜ν”„', 'μ΅œμ†Œ', λΌλŠ” ν‚€μ›Œλ“œκ°€ λ“±μž₯ν•˜μ—¬ λ°μ΄ν¬μŠ€νŠΈλΌμΈκ°€ ν•˜κ³  κ·Έμͺ½μœΌλ‘œ λ°©ν–₯을 ν‹€μ—ˆλ‹€.

μ—¬λŠ 데이크슀트라 μ•Œκ³ λ¦¬μ¦˜ 처럼 ν­νŒŒν•œ 횟수λ₯Ό κΈ°μ€€μœΌλ‘œ μ •λ ¬ν•˜λ©° κ·Έλž˜ν”„λ₯Ό νƒμƒ‰ν•˜λ˜, μž₯애물을 λ§Œλ‚˜λ©΄ 그곳을 ν­νŒŒν•΄μ£ΌλŠ” 방식을 μƒκ°ν–ˆμ—ˆλ‹€. μ²˜μŒμ—λŠ” μž₯애물을 λ§Œλ‚˜λ©΄ ν•΄λ‹Ή μž₯애물을 μ œκ±°ν•˜κΈ° μœ„ν•΄ D * D 반볡 ν•˜λ©΄μ„œ 폭파된 λ³΄λ“œλ₯Ό μ—…λ°μ΄νŠΈ ν•΄μ£Όμ—ˆλ‹€. 

 

ν•˜μ§€λ§Œ μ΄λ ‡κ²Œ κ΅¬ν˜„ν•œλ‹€λ©΄ N * M * D^2둜 μ œν•œ μ‹œκ°„ 2초 μ•ˆμ— ν†΅κ³Όν•˜μ§€ λͺ»ν•œλ‹€. (500 * 500 * 100^2 = 2,500,000,000)

그럼 N * M * D둜 ν•΄κ²°ν•΄μ•Ό ν•˜λŠ” λ¬Έμ œλΌλŠ” 것을 μ•Œ 수 μžˆλ‹€. 

 

πŸ“š 문제 ν’€μ΄

그럼 D * D λ°˜λ³΅ν•˜μ§€ μ•ŠμœΌλ©΄μ„œ μ–΄λ–»κ²Œ 폭파λ₯Ό ν•  수 μžˆμ„κΉŒ. μ•„μ΄λ””μ–΄λŠ” 직접 ν­νŒŒν•˜μ§€ μ•Šκ³  μ›Œν”„ν•˜λŠ” 것이닀. 

 

N = 9, M = 9, D = 3 μΌλ•Œ, ν˜„μž¬ (4, 4)에 μœ„μΉ˜ν–ˆμžˆλ‹€κ³  κ°€μ •ν•˜μž.

(4, 4)에 μœ„μΉ˜

 

D = 3μ΄λ‹ˆ ν•œλ²ˆ ν­νŒŒν•˜λ©΄ μ•„λž˜ 그림처럼 D * D λ²”μœ„μ— νš¨κ³Όκ°€ μžˆμ„ 것이닀. 

 

 

μ € μœ„μΉ˜μ—μ„œ ν­νŒŒμ‹œμΌœμ„œ 이동할 수 μžˆλŠ” 것을 νŒŒμ•…ν•΄λ³΄λ©΄ μ•„λž˜ κ·Έλ¦Όκ³Ό κ°™λ‹€.

 

 

 

μ •λ¦¬ν•˜μžλ©΄ μ•„λž˜ 주황색 λΆ€λΆ„μœΌλ‘œ μΉ ν•΄μ ΈμžˆλŠ” 뢀뢄은 ν˜„μž¬ μœ„μΉ˜ (4, 4)μ—μ„œ 폭탄 ν•œλ²ˆ ν„°λœ¨λ €μ„œ 이동할 수 μžˆλŠ” λ²”μœ„μ΄λ‹€. 

 

 

 

 

D * D λŒλ©΄μ„œ λ³΄λ“œ μ—…λ°μ΄νŠΈ ν•  ν•„μš” 없이 ν˜„μž¬ μœ„μΉ˜μ—μ„œ 폭탄 터지고 λ‚œ ν›„μ˜ μœ„μΉ˜λ‘œ μ›Œν”„ν•˜λ©΄ λœλ‹€!

λ¬Όλ‘  ν˜„μž¬ μœ„μΉ˜μ—μ„œ μƒν•˜μ’Œμš°λ‘œλ„ 탐색을 ν•œλ‹€. 

 

주황색 λ²”μœ„ μ•ˆμ— μžˆλŠ” 곳은 탐색 λͺ»ν•˜λŠ”κ±° μ•„λ‹Œκ°€? ν•˜λŠ” 의문이 λ“€ 수 μžˆμ§€λ§Œ, 폭탄을 λ– λœ¨λ¦° 횟수둜 μ •λ ¬ν•΄μ„œ νƒμƒ‰ν•˜κΈ° λ•Œλ¬Έμ— 주황색 λ²”μœ„ μ•ˆμ΄ λͺ¨λ‘ μž₯애물이 μ—†λ‹€λ©΄ 빠짐없이 νƒμƒ‰ν•˜κ²Œ 되고, μž₯애물이 μžˆλ‹€λ©΄, ν˜„μž¬ μœ„μΉ˜κ°€ μ•„λ‹Œ λ‹€λ₯Έ μœ„μΉ˜μ—μ„œ μ–Έμ  κ°€ λ°©λ¬Έν•˜κ²Œ λ˜μ–΄μžˆλ‹€. 

 

그럼 이제 데이크슀트라 μ•Œκ³ λ¦¬μ¦˜μ„ κ΅¬ν˜„ν•˜λ©΄ 될까?

λ¬Όλ‘  데이크슀트라 μ•Œκ³ λ¦¬μ¦˜μœΌλ‘œλ„ ν’€ 수 μžˆλ‹€! ν•˜μ§€λ§Œ μ’€ 더 관찰해보면, ν˜„μž¬ μœ„μΉ˜μ—μ„œ μƒν•˜μ’Œμš°λ‘œ 탐색할 λ•Œ μž₯애물이 μ—†λ‹€λ©΄ 폭파 카운트 증가 없이 이동 κ°€λŠ₯ν•˜κ³ , D 만큼 μ›Œν”„ λ›Έ λ•Œμ—λŠ” 폭파 카운트 1 μ¦κ°€ν•˜λ©΄μ„œ μ΄λ™ν•˜λŠ” 것을 μ•Œ 수 μžˆλ‹€.

 

(0κ³Ό 1... 0κ³Ό 1의 λ―Έλ‘œκ°€ 보여)

 

κ·Έλ ‡λ‹€ 0 - 1 bfsλ‘œλ„ 문제λ₯Ό ν•΄κ²°ν•  수 μžˆλ‹€. μƒν•˜μ’Œμš° 탐색할 λ•Œμ—λŠ” 큐 μ™Όμͺ½μ— μΆ”κ°€ν•΄μ£Όκ³ , D μ›Œν”„ λ›Έ λ•Œμ—λŠ” 큐 였λ₯Έμͺ½μ— μΆ”κ°€ν•΄μ£Όλ©° νƒμƒ‰ν•˜λ©΄ 더 효율적인 μ‹œκ°„ λ³΅μž‘λ„λ‘œ λ¬Έμ œκ°€ ν•΄κ²° κ°€λŠ₯ν•˜λ‹€.

 

πŸ’» μ½”λ“œ

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
from collections import deque
import sys
input = sys.stdin.readline
 
n,m,d = map(int,input().split())
 
board = [list(input().rstrip()) for _ in range(n)]
 
 
bomb = [[float('inf')] * m for _ in range(n)]
bomb[0][0= 0
 
queue = deque([(0,0,0)]) # cnt, y, x, board
 
while queue:
    cnt, y, x = queue.popleft()
    if y==n-1 and x==m-1:
        break
    if bomb[y][x] < cnt: continue
 
    # μƒν•˜μ’Œμš° νƒμƒ‰
    for dy,dx in ((0,-1), (0,1), (1,0), (-1,0)):
        ny,nx = y + dy, x + dx
 
        if ny < 0 or nx < 0 or ny >= n or nx >= m: continue
        if board[ny][nx] == '.' and bomb[y][x] < bomb[ny][nx]:
            bomb[ny][nx] = bomb[y][x]
            queue.appendleft((bomb[ny][nx], ny, nx))
 
    # d μ›Œν”„ λ›°λ©° νƒμƒ‰    
    for ddy,ddx in ((0,d), (0,-d), (-d,0), (d,0)):
        for i in range(-d+1, d):
            ny = y + ddy + (i if ddy == 0 else 0
            nx = x + ddx + (i if ddx == 0 else 0)
 
            # λ²”μœ„ λ„˜μ–΄κ°„ κ²½μš° κ²½κ³„λ‘œ μ„€μ •
            if ny < 0 or nx < 0 or ny >= n or nx >=m: 
                ny = max(0, ny)
                nx = max(0, nx)
                ny = min(ny, n - 1)
                nx = min(nx, m - 1)
 
            if bomb[y][x] + 1 < bomb[ny][nx]:
                bomb[ny][nx] = bomb[y][x] + 1
                queue.append((bomb[ny][nx], ny, nx))
 
print(bomb[n-1][m-1])
 
 
cs

 

 

🍭 μ‹œν–‰μ°©μ˜€

 

 

 

0-1 bfs: 1436 ms

데이크슀트라: 1768 ms

 

πŸ”— 문제링크