๐Ÿน.dev
[BOJ 4112] Mosaic2024๋…„ 3์›” 9์ผ ์ƒ์„ฑ(2024๋…„ 3์›” 10์ผ ์ˆ˜์ •)์•Œ๊ณ ๋ฆฌ์ฆ˜๋‹ค์ด๋‚˜๋ฏน ํ”„๋กœ๊ทธ๋ž˜๋ฐ๋น„ํŠธ๋งˆ์Šคํ‚น๋น„ํŠธํ•„๋“œ๋ฅผ ์ด์šฉํ•œ ๋‹ค์ด๋‚˜๋ฏน ํ”„๋กœ๊ทธ๋ž˜๋ฐ

๋ฌธ์ œ ์†Œ๊ฐœ

๋ฌธ์ œ ๋งํฌ : https://boj.kr/4112

Tier : Platinum I

Tag : DP, Bitmasking, Bitfield DP

2x2 ๋ธ”๋ก, ํšŒ์ „ ๊ฐ€๋Šฅํ•œ ใ„ฑ์ž ๋ธ”๋ก์„ ์ด์šฉํ•˜์—ฌ N * M ํฌ๊ธฐ์˜ ์นธ์„ ๋ชจ๋‘ ์ฑ„์šฐ๋Š” ๋ฐฉ๋ฒ•์˜ ์ˆ˜๋ฅผ ๊ตฌํ•˜๋Š” ๋ฌธ์ œ์ž…๋‹ˆ๋‹ค.

ํ’€์ด

1. ๋ธŒ๋ฃจํŠธ ํฌ์Šค ํ’€์ด๋ฅผ ๋จผ์ € ์ƒ๊ฐํ•ด๋ณด๊ธฐ

๋จผ์ € ๋ธŒ๋ฃจํŠธ ํฌ์Šค๋กœ ํ‘ธ๋Š” ๋ฐฉ๋ฒ•์„ ์ƒ๊ฐํ•ด๋ด…์‹œ๋‹ค.

๋ฌธ์ œ์— ๋”ฐ๋ฅด๋ฉด, N๊ฐœ์˜ ํ–‰๊ณผ M๊ฐœ์˜ ์—ด๋กœ ๊ตฌ์„ฑ๋œ ์นธ์ด ์กด์žฌํ•ฉ๋‹ˆ๋‹ค.

1ํ–‰ 1์—ด๋ถ€ํ„ฐ ๋ธ”๋Ÿญ์„ ๋†“์€ ๋’ค ๊ทธ ๋‹ค์Œ ๋นˆ ์นธ์„ ์ฐพ์•„ ๋ธ”๋Ÿญ์„ ๋†“๋Š” ์‹์œผ๋กœ ์ง„ํ–‰๋˜๋‹ค๊ฐ€, ๋งˆ์ง€๋ง‰์— ๋ธ”๋Ÿญ์„ ๋นˆ ์นธ ์—†์ด ๋ชจ๋‘ ์ฑ„์šธ ์ˆ˜ ์žˆ์œผ๋ฉด ํ•˜๋‚˜์˜ ๋ฐฉ๋ฒ•์œผ๋กœ ๊ฐ„์ฃผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ฆ‰, ํŠน์ • ์œ„์น˜์— ํŠน์ • ๋ธ”๋ก์„ ๋†“์œผ๋ฉด์„œ ์ƒ๊ธฐ๋Š” ๋‹ค์–‘ํ•œ ๋ถ„๊ธฐ์ ์— ๋Œ€ํ•ด ๋ชจ๋‘ ํƒ์ƒ‰ํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ๊ตฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜, ์ด๋Ÿฌํ•œ ๋ฐฉ์‹์€ (๋ฐฑํŠธ๋ž˜ํ‚น๊ณผ ๊ฐ™์€ ์ตœ์ ํ™”๋ฅผ ๊ฑฐ์ณ๋„) N๊ณผ M์ด ์ปค์งˆ์ˆ˜๋ก ํŒ๋‹จํ•ด์•ผ ํ•˜๋Š” ๋ฐฉ๋ฒ•์˜ ์ˆ˜๊ฐ€ ๊ธฐํ•˜๊ธ‰์ˆ˜์ ์œผ๋กœ ์ฆ๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ, ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์„ ๊ณ ์•ˆํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

2. DP๋ฅผ ํ†ตํ•ด ์ตœ์ ํ™”ํ•˜๊ธฐ

DP๋Š” ๋ธŒ๋ฃจํŠธ ํฌ์Šค์™€ ์—ฐ๊ด€์ด ๊นŠ์Šต๋‹ˆ๋‹ค. ๋ชจ๋“  ๊ฒฝ์šฐ๋ฅผ ํƒ์ƒ‰ํ•˜์—ฌ ์ตœ์ ์˜ ํ•ด๋ฅผ ๊ตฌํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ๋ธŒ๋ฃจํŠธ ํฌ์Šค์™€ DP ๋ชจ๋‘ ํ•ด๋‹น๋˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

๋Œ€์‹ , DP๋Š” ํƒ์ƒ‰ ๊ณผ์ •์„ ๊ฑฐ์น˜๋ฉด์„œ ์žฌํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋ถ€๋ถ„์€ ์ตœ๋Œ€ํ•œ ์žฌํ™œ์šฉํ•˜์—ฌ ์—ฐ์‚ฐ ํšŸ์ˆ˜๋ฅผ ์ตœ์†Œํ™”ํ•˜๋Š”๋ฐ์š”, ์ด๋ฅผ ๋ฉ”๋ชจ์ด์ œ์ด์…˜ (Memoization)์ด๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

์ด ๋ฌธ์ œ ๋˜ํ•œ DP๋กœ ์—ฐ์‚ฐ ํšŸ์ˆ˜๋ฅผ ์ตœ์†Œํ™”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์–ด๋–ป๊ฒŒ ์ตœ์ ํ™”๋ฅผ ํ•  ์ˆ˜ ์žˆ์„๊นŒ์š”?

ํŠน์ • ๋ฌธ์ œ๋ฅผ DP๋กœ ์ ‘๊ทผํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š”, ์ž„์˜์˜ ์œ„์น˜์— ๋Œ€ํ•ด ์ ํ™”์‹์„ ์„ธ์šธ ์ˆ˜ ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

3. ์ ํ™”์‹์„ ๋น„๋กฏํ•œ ์ผ๋ฐ˜์ ์ธ ๊ทœ์น™ ์ฐพ๊ธฐ

๋ธŒ๋ฃจํŠธ ํฌ์Šค๋กœ ์ ‘๊ทผํ•  ๋•Œ๋ฅผ ๋– ์˜ฌ๋ ค๋ด…์‹œ๋‹ค. ํŠน์ • ์œ„์น˜์— ํŠน์ • ๋ธ”๋ก์„ ๋†“๋Š” ๊ฒฝ์šฐ,

์ด์ „์— ํ›‘์€ ์นธ์€ ์ƒ๊ฐํ•˜์ง€ ์•Š๊ณ  ๊ทธ ๋‹ค์Œ ์นธ๋“ค์— ๋Œ€ํ•ด ๋ฐฉ๋ฒ•์˜ ์ˆ˜๋ฅผ ๋”ฐ์ง€๊ฒŒ ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ด๋•Œ, dp[n][m][?] = (ํŠน์ • ์œ„์น˜์—์„œ ํŠน์ • ๋ธ”๋ก์„ ๋†“์„ ๊ฒฝ์šฐ ์ƒ๊ธฐ๋Š” ๋ฐฉ๋ฒ•์˜ ์ˆ˜)๋กœ ์ ํ™”์‹์„ ๋‚˜ํƒ€๋‚ผ ์ˆ˜ ์žˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

n๊ณผ m์€ ํŠน์ • ์œ„์น˜๋ฅผ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์„œ ?๋Š” ๋ฌด์—‡์„ ๋‚˜ํƒ€๋‚ด์•ผ ํ• ๊นŒ์š”?

ํŠน์ • ๋ธ”๋ก์„ ๋†“์„ ๋•Œ, ๋ธ”๋Ÿญ์€ (๋นˆ ์นธ์„ ํฌํ•จํ•˜์—ฌ) ํ•ญ์ƒ 2x2์นธ์„ ์ฐจ์ง€ํ•˜๋ฏ€๋กœ ๊ทธ ์•„๋ž˜ ํ–‰์—'๋„' ์˜ํ–ฅ์„ ๋ผ์น˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜, ํŠน์ • ์œ„์น˜๋ฅผ ๊ธฐ์ค€์œผ๋กœ ๋ฐ”๋กœ ์•„๋ž˜ ํ–‰์—'๋งŒ' ์˜ํ–ฅ์„ ๋ผ์น˜๊ฒŒ ๋˜๋ฏ€๋กœ k์˜ ๋ฒ”์œ„๋ฅผ (ํ˜„์žฌ ์œ„์น˜) ~ (์˜ํ–ฅ์ด ๋ผ์น˜๋Š” ์œ„์น˜)๋กœ ์ขํž ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ฆ‰, ํ˜„์žฌ ์œ„์น˜๋ฅผ 0๋ฒˆ์งธ๋ผ ํ•˜๋ฉด ์–ด๋–ค ๋ธ”๋ก์„ ๋†“์•„๋„ M + 1๋ฒˆ์งธ ์œ„์น˜๊นŒ์ง€๋งŒ ์˜ํ–ฅ์„ ๋ผ์น  ์ˆ˜๋ฐ–์— ์—†์Šต๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ, Bitmasking์„ ํ™œ์šฉํ•˜์—ฌ ํ•ด๋‹น ๋ฒ”์œ„์— ์กด์žฌํ•  ์ˆ˜ ์žˆ๋Š” ๋ธ”๋Ÿญ์˜ ๋ชจ๋“  ํŒจํ„ด๋ฅผ ?๋กœ ์ •ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

4. Top-Down Bitfield DP๋กœ ๊ตฌํ•˜๊ธฐ

์œ„์˜ ๊ณผ์ •์„ ํ†ตํ•ด, ์ ํ™”์‹์€

dp[n][m][k] = (ํŠน์ • ์œ„์น˜์—์„œ ํŠน์ • ๋ธ”๋ก์„ ๋†“์„ ๊ฒฝ์šฐ ์ƒ๊ธฐ๋Š” ๋ฐฉ๋ฒ•์˜ ์ˆ˜) ๋กœ ๋‚˜ํƒ€๋‚ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

(n, m์€ ํŠน์ • ์œ„์น˜, k๋Š” ํ•ด๋‹น ๋ฒ”์œ„์— ์กด์žฌํ•  ์ˆ˜ ์žˆ๋Š” ๋ธ”๋Ÿญ์˜ ํŒจํ„ด)

k๋Š” 2 ^ (M + 2) ์ด๋ฏ€๋กœ, ์‹œ๊ฐ„ ๋ณต์žก๋„๋Š” O(NM2^(M + 2)) ๊ฐ€ ๋ฉ๋‹ˆ๋‹ค.

์•„๋ž˜์˜ ์ฝ”๋“œ๋ฅผ ํ†ตํ•ด ์ ํ™”์‹์— ๋Œ€ํ•œ ํ’€์ด ๊ณผ์ •์„ ํ™•์ธํ•˜์„ธ์š”.

์ฝ”๋“œ

โš ๏ธ Python ์–ธ์–ด ํŠน์„ฑ์ƒ ๋Š๋ฆฌ๊ธฐ ๋•Œ๋ฌธ์—, ์ด ์ฝ”๋“œ๋กœ ์ œ์ถœํ•  ๊ฒฝ์šฐ ์‹œ๊ฐ„ ์ดˆ๊ณผ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ, ๋ฏธ๋ฆฌ ๋ชจ๋“  ๊ฒฐ๊ณผ๋ฅผ ๋ฝ‘์•„๋†“๊ณ  ์ธ๋ฑ์‹ฑํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ํ’€์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

solution.py
1import sys
2input = lambda: sys.stdin.readline().rstrip()
3MOD = int(1e6)
4
5def solve(N, M):
6 memo = [[-1] * (1 << (M + 2)) for _ in range(N * M)]
7
8 def find(idx, bit):
9 row, col = idx // M, idx % M
10
11 if memo[idx][bit] >= 0:
12 return memo[idx][bit]
13
14 # ๋งˆ์ง€๋ง‰ ํ–‰๊นŒ์ง€ ์˜ค๋ฉด, ๋” ์ด์ƒ ๋ธ”๋ก์„ ์ฑ„์šธ ์ˆ˜ ์—†๋‹ค.
15 if row == N - 1:
16 memo[idx][bit] = int(bit == (1 << (M - col)) - 1)
17 return memo[idx][bit]
18
19 result = 0
20
21 # ํ˜„์žฌ ๋ธ”๋ก์ด ์ฑ„์›Œ์ง„ ๊ฒฝ์šฐ ๋„˜์–ด๊ฐ„๋‹ค.
22 if bit & 1:
23 result = (result + find(idx + 1, bit >> 1)) % MOD
24
25 # 2x2 Block
26 if col + 1 < M and bit & (3 | (3 << M)) == 0:
27 result = (result + find(idx + 2, (bit | (3 << M)) >> 2)) % MOD
28
29 # left-top
30 if col + 1 < M and bit & (3 | (1 << M)) == 0:
31 result = (result + find(idx + 2, (bit | (1 << M)) >> 2)) % MOD
32
33 # right-top
34 if col + 1 < M and bit & (3 | (2 << M)) == 0:
35 result = (result + find(idx + 2, (bit | (2 << M)) >> 2)) % MOD
36
37 # left-bottom
38 if col + 1 < M and bit & (1 | (3 << M)) == 0:
39 result = (result + find(idx + 1, (bit | (3 << M)) >> 1)) % MOD
40
41 # right-bottom
42 if col > 0 and bit & (1 | (3 << (M - 1))) == 0:
43 result = (result + find(idx + 1, (bit | (3 << (M - 1))) >> 1)) % MOD
44
45 memo[idx][bit] = result
46 return result
47
48 return find(0, 0)
49
50if __name__ == '__main__':
51 while data := input():
52 N, M = map(int, data.split())
53
54 if N == M == 0:
55 break
56
57 print(solve(M, N))
58
solution.py
1import sys
2input = lambda: sys.stdin.readline().rstrip()
3MOD = int(1e6)
4
5def solve(N, M):
6 memo = [[-1] * (1 << (M + 2)) for _ in range(N * M)]
7
8 def find(idx, bit):
9 row, col = idx // M, idx % M
10
11 if memo[idx][bit] >= 0:
12 return memo[idx][bit]
13
14 # ๋งˆ์ง€๋ง‰ ํ–‰๊นŒ์ง€ ์˜ค๋ฉด, ๋” ์ด์ƒ ๋ธ”๋ก์„ ์ฑ„์šธ ์ˆ˜ ์—†๋‹ค.
15 if row == N - 1:
16 memo[idx][bit] = int(bit == (1 << (M - col)) - 1)
17 return memo[idx][bit]
18
19 result = 0
20
21 # ํ˜„์žฌ ๋ธ”๋ก์ด ์ฑ„์›Œ์ง„ ๊ฒฝ์šฐ ๋„˜์–ด๊ฐ„๋‹ค.
22 if bit & 1:
23 result = (result + find(idx + 1, bit >> 1)) % MOD
24
25 # 2x2 Block
26 if col + 1 < M and bit & (3 | (3 << M)) == 0:
27 result = (result + find(idx + 2, (bit | (3 << M)) >> 2)) % MOD
28
29 # left-top
30 if col + 1 < M and bit & (3 | (1 << M)) == 0:
31 result = (result + find(idx + 2, (bit | (1 << M)) >> 2)) % MOD
32
33 # right-top
34 if col + 1 < M and bit & (3 | (2 << M)) == 0:
35 result = (result + find(idx + 2, (bit | (2 << M)) >> 2)) % MOD
36
37 # left-bottom
38 if col + 1 < M and bit & (1 | (3 << M)) == 0:
39 result = (result + find(idx + 1, (bit | (3 << M)) >> 1)) % MOD
40
41 # right-bottom
42 if col > 0 and bit & (1 | (3 << (M - 1))) == 0:
43 result = (result + find(idx + 1, (bit | (3 << (M - 1))) >> 1)) % MOD
44
45 memo[idx][bit] = result
46 return result
47
48 return find(0, 0)
49
50if __name__ == '__main__':
51 while data := input():
52 N, M = map(int, data.split())
53
54 if N == M == 0:
55 break
56
57 print(solve(M, N))
58