Skip to content

Commit 3ef62f5

Browse files
committed
[Passed] 미생물 연구 (223ms, 24MB)
1 parent 1dc407c commit 3ef62f5

2 files changed

Lines changed: 173 additions & 0 deletions

File tree

‎261008/미생물 연구/README.md‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# [미생물 연구](https://www.codetree.ai/frequent-problems/samsung-sw/problems/microbial-research)
2+
3+
**SW 역량 테스트** › 2025 상반기 오후 1번 문제
4+
5+
| 항목 | 내용 |
6+
|---|---|
7+
| 난이도 | 13 |
8+
| 유형 | Simulation, BFS |
9+
| 경험치 | 0 XP |
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
import sys
2+
from collections import deque
3+
4+
sys.stdin = open('input.txt')
5+
6+
"""
7+
NxN 정사각형 배양용기
8+
좌측 하단의 좌표: (0,0)
9+
가장 우측 상단의 좌표: (N,N)
10+
11+
Q번의 실험
12+
1. 미생물 투입
13+
- 좌측 하단 (r1, c1), 우측 상단 (r2,c2)인 직사각형 영역에 미생물 투입
14+
- 다른 미생물이 존재한다면 기존 미생물 없어지고 영역에 새 미생물만 남게 됨
15+
- 기존 미생물 무리 A가 B에게 잡아먹히면서 A 영역이 둘 이상으로 나눠지면 A 나눠진 A 미생물은 용기에서 모두 사라짐
16+
17+
2. 배양용기 이동
18+
- 모든 미생물 새 배양용기로 이동 (새 배양용기의 크기는 기존과 동일)
19+
- 기존 배양용기에 미생물이 아예 없을때까지 반복
20+
- 기존 배양 용기에 있는 무리 중 가장 영역이 넓은 무리 선택 (둘 이상이면 먼저 투입된 것)
21+
- 선택된 미생물 새 배양용기에 옮김
22+
- 이때 기존용기에서의 무리 형태는 유지
23+
- 미생물이 배양 용기의 범위 벗어나지않고 다른 미생물과 겹치지 않아야함
24+
- 이 조건 내에서 최대한 x 좌표가 작게 옮겨야함. (둘 이상이라면 최대한 y좌표가 작게)
25+
- 옮기면서 어떤 곳에도 둘 수 없는 미생물 무리는 그냥 소멸함
26+
27+
3. 기록
28+
- 상하좌우로 맞닿은 면이 있는 무리: 인접한 무리
29+
- 모든 인접한 무리 쌍 확인. 중복확인은 x
30+
- 두 무리의 넓이를 곱한만큼의 성과
31+
- 이 모든 성과를 더한 값이 결과 -> 기록
32+
33+
각 실험의 결과를 출력하자
34+
"""
35+
36+
N, Q = map(int, input().split())
37+
bacteria = []
38+
for _ in range(Q):
39+
r1, c1, r2, c2 = map(int, input().split())
40+
bacteria.append([r1, c1, r2, c2])
41+
42+
grid = [[0] * N for _ in range(N)]
43+
44+
dr = [-1, 0, 1, 0] # 상,우,하,좌 (시계방향)
45+
dc = [0, 1, 0, -1] # 상,우,하,좌 (시계방향)
46+
47+
48+
def in_range(r, c):
49+
if 0 <= r < N and 0 <= c < N:
50+
return True
51+
else:
52+
return False
53+
54+
55+
def put_bacteria(r1, c1, r2, c2, num):
56+
for i in range(r1, r2):
57+
for j in range(c1, c2):
58+
grid[i][j] = num
59+
60+
61+
def make_group(): # 무리를 그룹으로 만들기
62+
group = {}
63+
for x in range(N):
64+
for y in range(N):
65+
num = grid[x][y]
66+
if num == 0:
67+
continue
68+
if num not in group:
69+
group[num] = []
70+
group[num].append((x, y))
71+
return group
72+
73+
74+
def check_connect(num, cells): # num번 무리, cells: 그 무리의 칸 목록
75+
start = cells[0]
76+
visited = [[False] * N for _ in range(N)]
77+
visited[start[0]][start[1]] = True
78+
count = 1
79+
80+
q = deque([start])
81+
while q:
82+
x, y = q.popleft()
83+
for k in range(4):
84+
nx, ny = x + dr[k], y + dc[k]
85+
if in_range(nx, ny) and grid[nx][ny] == num and not visited[nx][ny]:
86+
visited[nx][ny] = True
87+
count += 1
88+
q.append((nx, ny))
89+
90+
return count == len(cells)
91+
92+
93+
def remove_split(): # 나뉜 무리를 제거
94+
group = make_group()
95+
for num, cells in group.items():
96+
if not check_connect(num, cells): # 만약에 나눠져있으면
97+
for x, y in cells:
98+
grid[x][y] = 0 # 해당 미생물은 모두 사라져야하므로 cells의 좌표를 모두 0으로
99+
100+
101+
def can_place(new, shape, bx, by): # shape을 (bx, by) 기준으로 new에 놓을 수 있는지
102+
for dx, dy in shape:
103+
x, y = bx + dx, by + dy
104+
if not in_range(x, y) or new[x][y] != 0:
105+
return False
106+
return True
107+
108+
109+
def move_bacteria(): # 새 배양 용기로 이동
110+
group = make_group()
111+
new = [[0] * N for _ in range(N)]
112+
113+
# 넓이 큰 순, 같으면 먼저 투입된(번호 작은) 순
114+
order = sorted(group, key=lambda num: (-len(group[num]), num))
115+
116+
for num in order:
117+
cells = group[num]
118+
min_x = min(x for x, y in cells)
119+
min_y = min(y for x, y in cells)
120+
shape = [(x - min_x, y - min_y) for x, y in cells] # 모양 (상대 위치)
121+
122+
placed = False
123+
for bx in range(N): # x가 작은 위치부터
124+
for by in range(N): # 같으면 y가 작은 위치부터
125+
if can_place(new, shape, bx, by):
126+
for dx, dy in shape:
127+
new[bx + dx][by + dy] = num
128+
placed = True
129+
break
130+
if placed:
131+
break
132+
# 어디에도 못 놓으면 아무것도 안 함 = 사라짐
133+
134+
for x in range(N): # 새 용기를 grid에 복사
135+
for y in range(N):
136+
grid[x][y] = new[x][y]
137+
138+
139+
def plus_result(): # 인접한 무리 쌍의 넓이 곱 합
140+
group = make_group()
141+
pairs = set() # 중복제거용
142+
for x in range(N):
143+
for y in range(N):
144+
a = grid[x][y] # 지금 칸의 무리 번호
145+
if a == 0:
146+
continue # 빈칸은 건너뜀
147+
for k in range(4): # 상하좌우 이웃 확인
148+
nx, ny = x + dr[k], y + dc[k]
149+
if in_range(nx, ny):
150+
b = grid[nx][ny] # 이웃 칸의 무리 번호
151+
if b != 0 and b != a: # 빈칸도 아니고 나와 다른 번호면 두 무리가 맞닿아 있는것
152+
pairs.add((min(a, b), max(a, b)))
153+
total = 0
154+
for a, b in pairs:
155+
total += len(group[a]) * len(group[b])
156+
return total
157+
158+
159+
for i in range(Q):
160+
r1, c1, r2, c2 = bacteria[i]
161+
put_bacteria(r1, c1, r2, c2, i + 1) # 번호는 1부터
162+
remove_split()
163+
move_bacteria()
164+
print(plus_result())

0 commit comments

Comments
 (0)